Ok so I was not passing the correct arguments.
Preconditons:
The portal user must exist.
For that user in patient_access_onsite
table:
portal_pwd_status
must be 1 or 3
portal_onetime
must be NULL
A client must be registered (check Administration > System > Api Clients) with the following scopes:
api:port patient/encounter.read patient/patient.read api:fhir
Note that even if you’re not trying to access a fhir api route, it’s a necessary scope or else this error is returned when trying to get token:
{
"error": "invalid_scope",
"error_description": "The requested scope is invalid, unknown, or malformed",
"hint": "Check the `api:port` scope",
"message": "The requested scope is invalid, unknown, or malformed"
}
Not sure if that’s a bug or intentional
Sample CURL request to log in
curl --request POST \
--url http://localhost:8300/oauth2/default/token \
--header 'Accept: application/json' \
--header 'Content-Type: multipart/form-data' \
--header 'content-type: multipart/form-data; boundary=---011000010111000001101001' \
--form username=wesley@wesleylima.com \
--form password=PASSWORDHERE \
--form grant_type=password \
--form client_id=CLIENT_ID_HERE \
--form 'scope=api:port patient/encounter.read patient/patient.read api:fhir' \
--form user_role=patient \
--form email=wesley@wesleylima.com
Note that both email and username are required even if your portal settings allow email-only login.
Sample Response:
{
"scope": "patient\/encounter.read patient\/patient.read",
"token_type": "Bearer",
"expires_in": 3600,
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJKU2pteGs0MmhnazNLRmVxdUFFUmlQQkRvZ3AyZDNjcHVybnpjRTJzZkZrIiwianRpIjoiMTZkMjM4ZjYwYjI4M2IwNWEyNGU1NzA2YTZiOWQwNmJiZDY3ZTViZDFjNmJhZWI1MTNmNjY3NzI0YThhZDhiODJlZjJmYzM2MTFiMmI2YTMiLCJpYXQiOjE2MTIwNDE0MTYsIm5iZiI6MTYxMjA0MTQxNiwiZXhwIjoxNjEyMDQ1MDE2LCJzdWIiOiI5MjljMmY4OS0xMWJkLTQzOTctYjZiNy1mYTgzMzdlNTNiNGUiLCJzY29wZXMiOlsiYXBpOnBvcnQiLCJwYXRpZW50XC9lbmNvdW50ZXIucmVhZCIsInBhdGllbnRcL3BhdGllbnQucmVhZCIsImFwaTpmaGlyIiwic2l0ZTpkZWZhdWx0Il19.EQxvPU3gRODh03-C1SZLRaE-4Zy5CbY7Hu6sQd1G2Od5oL1MWw_rWGyj3mtNSJyqj3JHgxl4JmPhAc0e0J4EHA9pB5TMFqTHXOhVe6KHZQZgyihpwT3PaGqjoQrT0xa_JQtgszoP_IRC76d1Dg5yJp37cq1XWGltMOhXMy_nJWkCDOvoSKAXeLbDGQgEyFRGQgAmIU5YbqY2Iqx6ltlb_TcvsawROJgZ_4si6FmNac32QGQNTizP690mIbCrBzLtShH0cM6MzQ3FnERWvIg0QGundKtvJOFGtSIlbrI0g3Ptq3MO1_oGkusqzXg_E3edF3713dxXe3beCFnxppHDCg"
}
Then with the access token, we can now get portal api routes for the logged in user!
curl --request GET \
--url http://localhost:8300/apis/default/portal/patient \
--header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJKU2pteGs0MmhnazNLRmVxdUFFUmlQQkRvZ3AyZDNjcHVybnpjRTJzZkZrIiwianRpIjoiMTZkMjM4ZjYwYjI4M2IwNWEyNGU1NzA2YTZiOWQwNmJiZDY3ZTViZDFjNmJhZWI1MTNmNjY3NzI0YThhZDhiODJlZjJmYzM2MTFiMmI2YTMiLCJpYXQiOjE2MTIwNDE0MTYsIm5iZiI6MTYxMjA0MTQxNiwiZXhwIjoxNjEyMDQ1MDE2LCJzdWIiOiI5MjljMmY4OS0xMWJkLTQzOTctYjZiNy1mYTgzMzdlNTNiNGUiLCJzY29wZXMiOlsiYXBpOnBvcnQiLCJwYXRpZW50XC9lbmNvdW50ZXIucmVhZCIsInBhdGllbnRcL3BhdGllbnQucmVhZCIsImFwaTpmaGlyIiwic2l0ZTpkZWZhdWx0Il19.EQxvPU3gRODh03-C1SZLRaE-4Zy5CbY7Hu6sQd1G2Od5oL1MWw_rWGyj3mtNSJyqj3JHgxl4JmPhAc0e0J4EHA9pB5TMFqTHXOhVe6KHZQZgyihpwT3PaGqjoQrT0xa_JQtgszoP_IRC76d1Dg5yJp37cq1XWGltMOhXMy_nJWkCDOvoSKAXeLbDGQgEyFRGQgAmIU5YbqY2Iqx6ltlb_TcvsawROJgZ_4si6FmNac32QGQNTizP690mIbCrBzLtShH0cM6MzQ3FnERWvIg0QGundKtvJOFGtSIlbrI0g3Ptq3MO1_oGkusqzXg_E3edF3713dxXe3beCFnxppHDCg'
Sample Response:
{
"validationErrors": [],
"internalErrors": [],
"data": {
"id": "27",
"pid": "13",
"uuid": "929c2f89-11bd-4397-b6b7-fa8337e53b4e",
"pubpid": "13",
"title": "",
"fname": "wesley",
"mname": "",
"lname": "li",
"ss": "",
"street": "t-street",
"postal_code": "",
"city": "",
"state": "",
"county": "",
"country_code": "",
"drivers_license": "",
"contact_relationship": "",
"phone_contact": "",
"phone_home": "",
"phone_biz": "",
"phone_cell": "",
"email": "wesley@wesleylima.com",
"DOB": "1989-06-29",
"sex": "Male",
"race": "",
"ethnicity": "",
"status": ""
}
}