1

I am try to figure out how to get Oauth 2 working in my python code.

import requests, json
import webbrowser

authorize_url = "https://tcfhirsandbox.com.au/oauth2/authorize"
token_url = "https://tcfhirsandbox.com.au/oauth2/token"
state = 'asdasdasdasdasdas'
scope = 'noscope'
callback_uri = "x-argonaut-app://HealthProviderLogin/"
test_api_url = "https://tcfhirsandbox.com.au/fhir/dstu2/Patient?identifier=RN000000200"
client_id = '6A605kYem9GmG38Vo6TTzh8IFnjWHZWtRn46K1hoxQ'
client_secret = 'POrisHrcdMvUKmaR6Cea0b8jtx-z4ewVWrnaIXASO-H3tB3g5MgPV7Vqty7OP8aEbSGENWRMkeVKZDdG7Pw'

authorization_redirect_url = authorize_url + '?response_type=code&state=' + state + '&client_id=' + client_id + '&scope='+scope+'&redirect_uri=' + callback_uri
webbrowser.open(authorization_redirect_url)

authorization_code = input("Code:")
data = {'grant_type': 'authorization_code', 'code': authorization_code, 'redirect_uri': callback_uri}
access_token_response = requests.post(token_url, data=data, verify=True, allow_redirects=True, auth=(client_id, client_secret))
tokens = json.loads(access_token_response.text)
access_token = tokens['access_token']

api_call_headers = {'Authorization': 'Bearer ' + access_token}
api_call_response = requests.get(test_api_url, headers=api_call_headers, verify=True)

print(api_call_response.status_code)
print (api_call_response.text)

The issue here is I have to manually input the code from the authorization URL. I want to automate it ! Thanks,

22/01/2021|09:54AM

Tried this

import requests, json
rom bs4 import BeautifulSoup
import mechanize

authorize_url = "https://tcfhirsandbox.com.au/oauth2/authorize"
token_url = "https://tcfhirsandbox.com.au/oauth2/token"
state = 'asdasdasdasdasdas'
scope = 'noscope'
callback_uri = "x-argonaut-app://HealthProviderLogin/"
test_api_url = "https://tcfhirsandbox.com.au/fhir/dstu2/Patient?identifier=RN000000200"
client_id = '6A605kYem9GmG38Vo6TTzh8IFnjWHZWtRn46K1hoxQ'
client_secret = 'POrisHrcdMvUKmaR6Cea0b8jtx-z4ewVWrnaIXASO-H3tB3g5MgPV7Vqty7OP8aEbSGENWRMkeVKZDdG7Pw'

 
OAuth_url = authorize_url + '?response_type=code&state=' + state + '&client_id=' + client_id + '&scope='+scope+'&redirect_uri=' + callback_uri
 
br = mechanize.Browser()
br.open(OAuth_url)
br.select_form(nr=0)
br.form['Username'] = 'my_username'
br.form['Password'] = 'my_password'
r = br.submit()
#print(r.read())
resp = r.read()
br.select_form(nr=0)
ac = br.form.click(name = 'Accept')
 
soup = BeautifulSoup(resp)
print(soup)
print(ac)
auth_code = str(ac)
code_list = auth_code.split("=")
cd_lst = code_list[1].split("&")
authorization_code = str(cd_lst[0])
print(authorization_code)
 
data = {'grant_type': 'authorization_code', 'code': authorization_code, 'redirect_uri': callback_uri}
access_token_response = requests.post(token_url, data=data, verify=True, allow_redirects=True, auth=(client_id, client_secret))
 
print(access_token_response.status_code)
tokens = json.loads(access_token_response.text)
access_token = tokens['access_token']
 
print(access_token)

I think I am close but still couldn't get it working. It is giving bad request (error code:400) as response.

If anyone can help with this would be awesome. Thanks

Rusty
  • 11
  • 5
  • Unless you're doing this as a learning exercise, consider using the SMART on FHIR client python library: https://github.com/smart-on-fhir/client-py/ – rmharrison Feb 06 '21 at 07:46

1 Answers1

0

TL;DR You're getting a 400 BAD_REQUEST because the OAuth_url isn't properly constructed. Try:

https://tcfhirsandbox.com.au/oauth2/authorize?
response_type=code&
state=asdasdasdasdasdas&client_id=6A605kYem9GmG38Vo6TTzh8IFnjWHZWtRn46K1hoxQ&
redirect_uri=x-argonaut-app://HealthProviderLogin/
scope=launch%2Fpatient+openid+fhirUser+patient%2F%2A.read&
aud=https://tcfhirsandbox.com.au/

The base url for the reference server you gave (https://tcfhirsandbox.com.au) doesn't resolve.

So I'll demonstrate using another reference server.

The OAuth_url you've constructed:

https://tcfhirsandbox.com.au/oauth2/authorize?
response_type=code&
state=asdasdasdasdasdas&client_id=6A605kYem9GmG38Vo6TTzh8IFnjWHZWtRn46K1hoxQ&
redirect_uri=x-argonaut-app://HealthProviderLogin/
scope=noscope&

A working OAuth_url with the reference server [^1]:

https://inferno.healthit.gov/reference-server/oauth/authorization?
response_type=code&
state=ad6458f9-240a-42b7-b314-05d0c3b2c7c9&
client_id=SAMPLE_CONFIDENTIAL_CLIENT_ID&
redirect_uri=https%3A%2F%2Finferno.healthit.gov%2Finferno%2Foauth2%2Fstatic%2F
redirect&
scope=launch%2Fpatient+openid+fhirUser+patient%2F%2A.read&
aud=https%3A%2F%2Finferno.healthit.gov%2Freference-server%2Fr4

You'll see two differences between the request you've constructed and reference, one of which is likely causing the 400 BAD_REQUEST:

  • scope (noscope isn't a valid SMART on FHIR scope [^2], which will cause most servers to error)
  • aud (you didn't include an aud query param, which is used as a claim in the access_token jwt you'll be issued)

[^1] Constructed using the Inferno test: https://inferno.healthit.gov/inferno/5g6OuEGN4hM/test_sets/test_procedure/

[^2] Direct link to supported SMART on FHIR scopes: http://hl7.org/fhir/smart-app-launch/scopes-and-launch-context/index.html#quick-start

rmharrison
  • 4,730
  • 2
  • 20
  • 35