Scoping searches by Patient
# support
j
Hey team - @joshua_kelly and I were exploring using tags to scope access to resources for a patient. We found that we're able to do search requests with the
_tag
parameter as expected (and the bundle response is correctly filtered) but we're wondering about the read operation: this may not be a medplum question, it might be a FHIR question in general - is it possible to scope a read request in a similar way? What are some alternatives we could consider if not?
r
Hi, @jakxz , a few questions: - I think I'm confused on the distinction between "reads" vs. "search" in this context - Is there reason you're using tags, rather than our AccessPolicy framework? Tags can get kind of clunky pretty fast , so our recommendation would be to use proper access policies (https://www.medplum.com/docs/auth/access-control)
Hi @jakxz - I just wanted to bump this and see if I could be helpful here?
j
Hey @rahul1 thanks for the follow up! Wanted to acknowledge this today, but - we’re going to pick up this work the week after next, it is our next priority after a bit of travel next week.
r
Awesome. Looking forward to it
j
Thanks again! Doing as much reading as I can in the meantime though; I’ll take as many links as you’ve got 🙂
p
Hey @rahul1 , Sorry to barge in here but @jakxz and I are pairing on this 😄 We notice the section “Patient Access” on your Access Control Doc, and this seems to perfectly represent the problem we are trying to solve. We have many different patients we are storing in Medplum, and obviously all of their related resources too. We want to use the Parameterized Policies, but are unsure how this would work on a User level. Do we need to have separate “Users” that will have separate credentials for each of our Patients? This would mean we would need to “login” to the MedplumClient whenever we want to retrieve resources from Medplum, right? How do you recommend we achieve this on a server to server pattern? (Our API is the only one talking to the
medplum-server
) Some background: - We use Client Credentials Login, this works because its server -> server and we bulk save all resources that belong to a Patient - We never actually get a Patient’s credentials when they login to their health plan. So we don’t want to create Users in Medplum if we don’t have to (we don’t have a credential to store) - There is this world of Compartments that may be beneficial also, but we’re a bit unsure how to leverage it.
And maybe as a follow up, is there anything top of mind on why using tags is clunky? Is it a DB index or lookup issue? We just don't want to shoot ourselves in the foot and end up in a worse state than where we are right now 😃 Thanks!
r
HI @phishin - I think I'm not quite understanding your use case, so I'll ask some questions. First off, to clarify some of the concepts around users and projects, you can check out this guide https://www.medplum.com/docs/auth/user-management-guide
Is the goal to have a user log into a front-end that is powered by Medplum, and only allow them to see their resources?
Or is this part of your data ingestion pipeline?
p
Hey - thanks for replying. > Is the goal to have a user log into a front-end that is powered by Medplum, and only allow them to see their resources? The second half of this is true - we want to make scoped API requests to Medplum that only return resources relevant to them. > Or is this part of your data ingestion pipeline? The data ingestion pipeline is working nicely right now. We fetch every possible resource we can from a third party (lets say Humana), and we can store things successfully in Medplum. We are currently using tags to scope Search requests to do this, but Reads are not following any form of access contorl currently. Meaning we do this on searches:
GET http://our.medplum.com/Coverage?_tag=our-fake-tag|123
Maybe to help clarify - Flexpa API needs to make server to server scoped requests to Medplum, as if we are a logged-in user. But we have no front-end for users to login, to. We just have an Access Token that works with Flexpa**
r
Ok I think we might be mixing up a few different concepts, so I'll to clarify: - If the goal is just to perform a search in medplum for all resources, of a certain type related to a Patient, you can do this using compartments. Medplum provides a non-standard search parameter,
_compartment
, to find all resources of a given type associacted with a patient. e.g. http://our.medplum.com/Coverage?_compartment=Patient/1234. The compartment is associated with the Coverage resource automatically by the server, using the compartment specification (https://www.hl7.org/fhir/compartmentdefinition.html) - If the goal is to block access to the server for some patients, then an access policy would be appropriate. However, this typically isn't done on a request-by-request basis, but more on session basis. If the medplum client is on the server, it doesn't seem like you'd want to actually block access from any patient data within the lifetime of the client's session
j
@rahul1 what would a read request (ie get a single resource) look like for getting a Coverage resource with ID 67890? Assuming that belongs to the patient with ID 1234 ofc
r
@jakxz are you asking about a standard FHIR resource by the
id
field of the resource in Medplum? That would just be a
GET [base]/Coverage/67890
http://hl7.org/fhir/R4/http.html#read
unless I'm missing something?
j
hey sorry I had an appointment yesterday - My question was trying to swap
search
in this statement for `read`: > If the goal is just to perform a search in medplum for all resources, of a certain type related to a Patient, you can do this using compartments. vs > If the goal is just to perform a
read
in medplum for
a specific resource
, of a certain type related to a Patient, you can do this using
_____
. Would the answer just be compartments again? 😮
But I didn't do a great job of reiterating the problem @phishin mentioned; we're trying to think about how to scope read requests for Resources to only return to the Patient they are associated with (the way we do with search requests); thanks for clarifying those concepts though, that is very helpful. here's an additional follow up q: > If the medplum client is on the server, it doesn't seem like you'd want to actually block access from any patient data within the lifetime of the client's session How is this done server side without special logins for each user (or patient), or would Medplum expect logins for each user?
i.e. is it possible to access control / compartment / scope resources programmatically for
read
requests?
p
Hey @rahul1 Sorry to barge in with more questions / thoughts, let me try and rephrase everything to make it a bit more clear Background: - We use Medplum primarily as a FHIR Datastore - We have a data ingestion pipeline that whenever a Patient links their health plan with Flexpa, we pull all of their resources and store them in our self hosted Medplum instance - We have one Project in Medplum, and we use a SuperAdmin User to save all resources into this Project. We use a client credentials auth flow to "login" to our Medplum instance. - We store the Patient resource first, and use that newly created
patient.id
to fix all of the references accross their resoruces (i.e. update all "reference": "Patient/old-id" to point to the newly generated ID) - We also tag each resource with the patient ID, this was our hacky way of achieveing access control on Search's, but not Reads. We make Search's like this:
GET our.medplum.com/Coverage?_tag=newly-created-patient-id|123
This works for Searches because we've tagged all Coverage resources that belong to this Patient with that tag. (Note: We know that this also works:
GET our.medplum.com/Coverage?patient=Patient/new-patient-id
) We make Reads like this:
GET our.medplum.com/Location/456
. The reason why the above isn't great, is because Reads are not access controlled at all. As far as we know, Reads don't allow a
_tag
param so we don't know for sure if this Location belongs to that Patient. (Or is accessible to that Patient) If a user starts guessing IDs, they can query for random Locations (or read any FHIR resource by ID) and see some PHI they shouldn't be able to see. So our problem: We want to make sure when we make a request to our Medplum instance for a given patient, we never return a resource that is shouldn't be seen by that patient. Is compartments the way to go here? Hope this helps 🙂 Happy to jump on a voice call if thats helpful too.
r
Thanks so much for the clarification guys, I think I see what's going on now. For read requests like
our.medplum.com/Location/456
, it seems like you're basically proxying those requests straight to medplum from your server. So for server-to-server communication, (where each user doesn't have their own access token), using AccessPolicies doesn't seem to make sense. That's because AccessPolicies are generally used to restrict access to a specific accessToken, not on a per-request basis. We've had some speculative conversations about have the
MedplumClient
act "on behalf of" a user per-request, but are still working on the design. For your immediate use-case, you can convert your "read" requests into a search via the
_id
parameter (http://hl7.org/fhir/R4/search.html#id) This means you could perform a search:
[base]/Location?_id=456&_compartment=Patient/new-patient
p
This is great - thanks @rahul1 ! all the best 😄
j
Thanks Rahul - that's an infinitely better title too
r
Just trying to make sure future generations can find this post 🙂
@joshua_kelly - See this thread re: access policies