fix: prior commit had CRLF line endings in sql/database.sql (#6461)
[openemr.git] / API_README.md
blob0bf4a5e02068eb6011828582b158e29845655b65
1 # OpenEMR REST API Documentation
3 ## REST API Table of Contents
4 - [Overview](API_README.md#overview)
5 - [Prerequisite](API_README.md#prerequisite)
6 - [Using API Internally](API_README.md#using-api-internally)
7 - [Multisite Support](API_README.md#multisite-support)
8 - [Authorization](API_README.md#authorization)
9     - [Scopes](API_README.md#scopes)
10     - [Registration](API_README.md#registration)
11         - [SMART on FHIR Registration](API_README.md#smart-on-fhir-registration)
12     - [Authorization Code Grant](API_README.md#authorization-code-grant)
13     - [Refresh Token Grant](API_README.md#refresh-token-grant)
14     - [Password Grant](API_README.md#password-grant)
15     - [Client Credentials Grant](API_README#client-credentials-grant)
16     - [Logout](API_README.md#logout)
17     - [OpenID Connect](API_README.md#openid-connect)
18     - [More Details](API_README.md#more-details)
19 - [Standard API Documentation](API_README.md#standard-api-documentation)
20 - [Patient Portal API Documentation](API_README.md#patient-portal-api-documentation)
21 - [FHIR API Documentation (in FHIR_README.md)](FHIR_README.md#fhir-api-documentation)
22     - [Capability Statement (in FHIR_README.md)](FHIR_README.md#capability-statement)
23     - [Provenance (in FHIR_README.md)](FHIR_README.md#Provenance-resources)
24     - [BULK FHIR Exports (in FHIR_README.md)](FHIR_README.md#bulk-fhir-exports)
25         - [System Export (in FHIR_README.md)](FHIR_README.md#bulk-fhir-exports)
26         - [Patient Export (in FHIR_README.md)](FHIR_README.md#bulk-fhir-exports)
27         - [Group Export (in FHIR_README.md)](FHIR_README.md#bulk-fhir-exports)
28     - [3rd Party SMART Apps (in FHIR_README.md)](FHIR_README.md#3rd-party-smart-apps)
29     - [Native Applications (in FHIR_README.md)](FHIR_README.md#native-applications)
30     - [Carecoordination Summary of Care (CCD) Generation (in FHIR_README.md)](FHIR_README.md#carecoordination-summary-of-care-docref-operation)
31         - [Overview Docref (in FHIR_README.md)](FHIR_README.md#overview-docref)
32         - [Generate CCDA (in FHIR_README.md)](FHIR_README.md#generate-ccda)
33         - [Details Docref (in FHIR_README.md)](FHIR_README.md#details-docref)
34 - [Security Settings](API_README.md#security)
35 - [For Developers](API_README.md#for-developers)
37 ## Overview
39 Easy-to-use JSON-based REST API for OpenEMR. FHIR is also supported, see FHIR API documentation [here](FHIR_README.md),
41 ## Prerequisite
43 Enable the Standard API service (/api/ endpoints) in OpenEMR menu: Administration->Globals->Connectors->"Enable OpenEMR Standard REST API"
45 ## Using API Internally
47 There are several ways to make API calls from an authorized session and maintain security:
49 -   See the script at tests/api/InternalApiTest.php for examples of internal API use cases.
51 ## Multisite Support
53 Multisite is supported by including the site in the endpoint. When not using multisite or using the `default` multisite site, then a typical path would look like `apis/default/api/patient`. If you are using multisite and using a site called `alternate`, then the path would look like `apis/alternate/api/patient`.
55 ## Authorization
57 OpenEMR uses OIDC compliant authorization for API. SSL is required and setting baseurl at Administration->Globals->Connectors->'Site Address (required for OAuth2 and FHIR)' is required. The listing of scopes can be found in below Scopes section.
59 ### Scopes
61 This is a listing of scopes:
62 - `openid` (Generic mandatory scope)
63 - `fhirUser`
64 - `online_access`
65 - `offline_access` (Will signal server to provide a refresh token)
66 - `launch`
67 - `launch/patient`
68 - `api:fhir` (fhir which are the /fhir/ endpoints)
69   - `patient/AllergyIntolerance.read`
70   - `patient/Appointment.read`
71   - `patient/Binary.read`
72   - `patient/CarePlan.read`
73   - `patient/CareTeam.read`
74   - `patient/Condition.read`
75   - `patient/Coverage.read`
76   - `patient/Device.read`
77   - `patient/DiagnosticReport.read`
78   - `patient/DocumentReference.read`
79   - `patient/DocumentReference.$docref`
80   - `patient/Encounter.read`
81   - `patient/Goal.read`
82   - `patient/Immunization.read`
83   - `patient/Location.read`
84   - `patient/MedicationRequest.read`
85   - `patient/Medication.read`
86   - `patient/Observation.read`
87   - `patient/Organization.read`
88   - `patient/Patient.read`
89   - `patient/Person.read`
90   - `patient/Practitioner.read`
91   - `patient/Procedure.read`
92   - `patient/Provenance.read`
93   - `system/AllergyIntolerance.read`
94   - `system/Binary.read`
95   - `system/CarePlan.read`
96   - `system/CareTeam.read`
97   - `system/Condition.read`
98   - `system/Coverage.read`
99   - `system/Device.read`
100   - `system/DiagnosticReport.read`
101   - `system/DocumentReference.read`
102   - `system/DocumentReference.$docref`
103   - `system/Encounter.read`
104   - `system/Goal.read`
105   - `system/Group.read`
106   - `system/Group.$export`
107   - `system/Immunization.read`
108   - `system/Location.read`
109   - `system/MedicationRequest.read`
110   - `system/Medication.read`
111   - `system/Observation.read`
112   - `system/Organization.read`
113   - `system/Patient.read`
114   - `system/Patient.$export`
115   - `system/Person.read`
116   - `system/Practitioner.read`
117   - `system/PractitionerRole.read`
118   - `system/Procedure.read`
119   - `system/Provenance.read`
120   - `system/*.$bulkdata-status`
121   - `system/*.$export`
122   - `user/AllergyIntolerance.read`
123   - `user/Binary.read`
124   - `user/CarePlan.read`
125   - `user/CareTeam.read`
126   - `user/Condition.read`
127   - `user/Coverage.read`
128   - `user/Device.read`
129   - `user/DiagnosticReport.read`
130   - `user/DocumentReference.read`
131   - `user/DocumentReference.$docref`
132   - `user/Encounter.read`
133   - `user/Goal.read`
134   - `user/Immunization.read`
135   - `user/Location.read`
136   - `user/MedicationRequest.read`
137   - `user/Medication.read`
138   - `user/Observation.read`
139   - `user/Organization.read`
140   - `user/Organization.write`
141   - `user/Patient.read`
142   - `user/Patient.write`
143   - `user/Person.read`
144   - `user/Practitioner.read`
145   - `user/Practitioner.write`
146   - `user/PractitionerRole.read`
147   - `user/Procedure.read`
148   - `user/Provenance.read`
149 - `api:oemr` (user api which are the /api/ endpoints)
150   - `user/allergy.read`
151   - `user/allergy.write`
152   - `user/appointment.read`
153   - `user/appointment.write`
154   - `user/dental_issue.read`
155   - `user/dental_issue.write`
156   - `user/document.read`
157   - `user/document.write`
158   - `user/drug.read`
159   - `user/encounter.read`
160   - `user/encounter.write`
161   - `user/facility.read`
162   - `user/facility.write`
163   - `user/immunization.read`
164   - `user/insurance.read`
165   - `user/insurance.write`
166   - `user/insurance_company.read`
167   - `user/insurance_company.write`
168   - `user/insurance_type.read`
169   - `user/list.read`
170   - `user/medical_problem.read`
171   - `user/medical_problem.write`
172   - `user/medication.read`
173   - `user/medication.write`
174   - `user/message.write`
175   - `user/patient.read`
176   - `user/patient.write`
177   - `user/practitioner.read`
178   - `user/practitioner.write`
179   - `user/prescription.read`
180   - `user/procedure.read`
181   - `user/soap_note.read`
182   - `user/soap_note.write`
183   - `user/surgery.read`
184   - `user/surgery.write`
185   - `user/transaction.read`
186   - `user/transaction.write`
187   - `user/vital.read`
188   - `user/vital.write`
189 - `api:port` (patient api which are the /portal/ endpoints) (EXPERIMENTAL)
190   - `patient/encounter.read`
191   - `patient/patient.read`
192   - `patient/appointment.read`
194 ### Registration
196 Here is an example for registering a client. A client needs to be registered before applying for grant to obtain access/refresh tokens. Note: "post_logout_redirect_uris" is optional and only used if client wants a redirect to its own confirmation workflow.
198 Note that all scopes are included in this example for demonstration purposes. For production purposes, should only include the necessary scopes.
200 ```sh
201 curl -X POST -k -H 'Content-Type: application/json' -i https://localhost:9300/oauth2/default/registration --data '{
202    "application_type": "private",
203    "redirect_uris":
204      ["https://client.example.org/callback"],
205    "post_logout_redirect_uris":
206      ["https://client.example.org/logout/callback"],
207    "client_name": "A Private App",
208    "token_endpoint_auth_method": "client_secret_post",
209    "contacts": ["me@example.org", "them@example.org"],
210    "scope": "openid offline_access api:oemr api:fhir api:port user/allergy.read user/allergy.write user/appointment.read user/appointment.write user/dental_issue.read user/dental_issue.write user/document.read user/document.write user/drug.read user/encounter.read user/encounter.write user/facility.read user/facility.write user/immunization.read user/insurance.read user/insurance.write user/insurance_company.read user/insurance_company.write user/insurance_type.read user/list.read user/medical_problem.read user/medical_problem.write user/medication.read user/medication.write user/message.write user/patient.read user/patient.write user/practitioner.read user/practitioner.write user/prescription.read user/procedure.read user/soap_note.read user/soap_note.write user/surgery.read user/surgery.write user/transaction.read user/transaction.write user/vital.read user/vital.write user/AllergyIntolerance.read user/CareTeam.read user/Condition.read user/Coverage.read user/Encounter.read user/Immunization.read user/Location.read user/Medication.read user/MedicationRequest.read user/Observation.read user/Organization.read user/Organization.write user/Patient.read user/Patient.write user/Practitioner.read user/Practitioner.write user/PractitionerRole.read user/Procedure.read patient/encounter.read patient/patient.read patient/AllergyIntolerance.read patient/CareTeam.read patient/Condition.read patient/Coverage.read patient/Encounter.read patient/Immunization.read patient/MedicationRequest.read patient/Observation.read patient/Patient.read patient/Procedure.read"
211   }'
214 Response:
215 ```sh
217     "client_id": "LnjqojEEjFYe5j2Jp9m9UnmuxOnMg4VodEJj3yE8_OA",
218     "client_secret": "j21ecvLmFi9HPc_Hv0t7Ptmf1pVcZQLtHjIdU7U9tkS9WAjFJwVMav0G8ogTJ62q4BATovC7BQ19Qagc4x9BBg",
219     "registration_access_token": "uiDSXx2GNSvYy5n8eW50aGrJz0HjaGpUdrGf07Agv_Q",
220     "registration_client_uri": "https:\/\/localhost:9300\/oauth2\/default\/client\/6eUVG0-qK2dYiwfYdECKIw",
221     "client_id_issued_at": 1604767861,
222     "client_secret_expires_at": 0,
223     "contacts": ["me@example.org", "them@example.org"],
224     "application_type": "private",
225     "client_name": "A Private App",
226     "redirect_uris": ["https:\/\/client.example.org\/callback"],
227     "token_endpoint_auth_method": "client_secret_post",
228     "scope": "openid offline_access api:oemr api:fhir api:port user/allergy.read user/allergy.write user/appointment.read user/appointment.write user/dental_issue.read user/dental_issue.write user/document.read user/document.write user/drug.read user/encounter.read user/encounter.write user/facility.read user/facility.write user/immunization.read user/insurance.read user/insurance.write user/insurance_company.read user/insurance_company.write user/insurance_type.read user/list.read user/medical_problem.read user/medical_problem.write user/medication.read user/medication.write user/message.write user/patient.read user/patient.write user/practitioner.read user/practitioner.write user/prescription.read user/procedure.read user/soap_note.read user/soap_note.write user/surgery.read user/surgery.write  user/transaction.read user/transaction.write user/vital.read user/vital.write user/AllergyIntolerance.read user/CareTeam.read user/Condition.read user/Coverage.read user/Encounter.read user/Immunization.read user/Location.read user/Medication.read user/MedicationRequest.read user/Observation.read user/Organization.read user/Organization.write user/Patient.read user/Patient.write user/Practitioner.read user/Practitioner.write user/PractitionerRole.read user/Procedure.read patient/encounter.read patient/patient.read patient/AllergyIntolerance.read patient/CareTeam.read patient/Condition.read patient/Coverage.read patient/Encounter.read patient/Immunization.read patient/MedicationRequest.read patient/Observation.read patient/Patient.read patient/Procedure.read"
232 #### SMART on FHIR Registration
234 SMART Enabled Apps are supported.
236 SMART client can be registered at <website>/interface/smart/register-app.php. For example https://localhost:9300/interface/smart/register-app.php
238 After registering the SMART client, can then Enable it in OpenEMR at Administration->System->API Clients
240 After it is enabled, the SMART App will then be available to use in the Patient Summary screen (SMART Enabled Apps widget).
242 See this github issue for an example of a Smart App installation: https://github.com/openemr/openemr/issues/4148
244 ### Authorization Code Grant
246 This is the recommended standard mechanism to obtain access/refresh tokens. This is done by using an OAuth2 client with provider url of `oauth2/<site>`; an example full path would be `https://localhost:9300/oauth2/default`.  Standard OAUTH2 clients will retrieve the authorize URL from the FHIR /metadata endpoint, but if you are building your own client you can access the metadata or go directly to the https://localhost:9300/oauth2/default/authorize endpoint.
248 Note that a refresh token is only supplied if the `offline_access` scope is provided when requesting authorization grant.
250 You will need to pass the scopes you are requesting, the redirect_uri (must be one that was registered at the time of your client registration), and a state parameter which can be any value.  Once authorization has finished the browser will be redirected to the URL specified in redirect_uri with an encrypted code value and the state value sent in the initial authorize request.
252 Example GET (this must be done in a browser):
254 GET /oauth2/default/authorize?client_id=yi4mnmVadpnqnJiOigkcGshuG-Kayiq6kmLqCJsYrk4&response_type=code&scope=launch%2Fpatient%20openid%20fhirUser%20offline_access%20patient%2FAllergyIntolerance.read%20patient%2FCarePlan.read%20patient%2FCareTeam.read%20patient%2FCondition.read%20patient%2FDevice.read%20patient%2FDiagnosticReport.read%20patient%2FDocumentReference.read%20patient%2FEncounter.read%20patient%2FGoal.read%20patient%2FImmunization.read%20patient%2FLocation.read%20patient%2FMedication.read%20patient%2FMedicationRequest.read%20patient%2FObservation.read%20patient%2FOrganization.read%20patient%2FPatient.read%20patient%2FPractitioner.read%20patient%2FProcedure.read%20patient%2FProvenance.read&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcallback&state=9512151b-e5ca-cb4b-1ddc-aaf4cd8c6ecc
257 The client application must then make a request for an access token by hitting the /token endpoint.  Note the redirect_uri MUST match what what was sent in /authorize endpoint.  If your application is registered as a public application you must include the client_id in the POST request.  If you are registered as a confidential app you must use HTTP Basic Authentication where the client_id is your username and the password is your client_secret.  HTTP Basic Authentication follows the algorithm of base64_encode(username:client_secret).  In PHP this would be base64_encode($client_id . ':' . $client_secret);  Note that this mechanism should ONLY be used over an encrypted protocol such as TLS to prevent leaking your client_secret.
259 Example Public Application POST
261 curl -X POST -k -H 'Content-Type: application/x-www-form-urlencoded'
262 'https://localhost:9300/oauth2/default/token'
263 --data 'grant_type=authorization_code&client_id=yi4mnmVadpnqnJiOigkcGshuG-Kayiq6kmLqCJsYrk4redirect_uri=https%3A%2F%2Fclient.example.org%2Fcallback&code=def50...'
266 Example Private Application POST
268 curl -X POST -k -H 'Content-Type: application/x-www-form-urlencoded' \
269     -H 'Authorization: Basic c3Z2TThFX1hISEhYUmtoZzUyeWoyNjdIOEYwQnpmT09pRmE4aUZBT290WTptbzZpZEFPaEU0UVYxb0lacUR5YTFHR1JHVGU5VDQzNWpzeTlRbWYxV2NiVFQ4NXhuZW5VdUpaUFR0bUZGT1QxVkhmYjZiclVvWWZ2Znd2NTFQejFldw==' \
270     'https://localhost:9300/oauth2/default/token' \
271     --data 'grant_type=authorization_code&client_id=yi4mnmVadpnqnJiOigkcGshuG-Kayiq6kmLqCJsYrk4redirect_uri=https%3A%2F%2Fclient.example.org%2Fcallback&code=def50...'
273 ### Refresh Token Grant
275 Note that a refresh token is only supplied if the `offline_access` scope is provided when requesting authorization or password grant.
277 Example:
279 ```sh
280 curl -X POST -k -H 'Content-Type: application/x-www-form-urlencoded'
281 -i 'https://localhost:9300/oauth2/default/token'
282 --data 'grant_type=refresh_token
283 &client_id=LnjqojEEjFYe5j2Jp9m9UnmuxOnMg4VodEJj3yE8_OA
284 &refresh_token=def5020089a766d16...'
287 Response:
289 ```json
291   "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJrYn...",
292   "token_type": "Bearer",
293   "expires_in": 3599,
294   "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJrYnl1RkRp...",
295   "refresh_token": "def5020017b484b0add020bf3491a8a537fa04eda12..."
299 ### Password Grant
301 Recommend not using this mechanism unless you know what you are doing. It is considered far less secure than the standard authorization code method. Because of security implications, it is not turned on by default. It can be turned on at Administration->Globals->Connectors->'Enable OAuth2 Password Grant (Not considered secure)'.
303 Note that all scopes are included in these examples for demonstration purposes. For production purposes, should only include the necessary scopes.
305 Note that a refresh token is only supplied if the `offline_access` scope is provided when requesting password grant.
307 Example for `users` role:
308 ```sh
309 curl -X POST -k -H 'Content-Type: application/x-www-form-urlencoded'
310 -i 'https://localhost:9300/oauth2/default/token'
311 --data 'grant_type=password
312 &client_id=LnjqojEEjFYe5j2Jp9m9UnmuxOnMg4VodEJj3yE8_OA
313 &scope=openid%20offline_access%20api%3Aoemr%20api%3Afhir%20user%2Fallergy.read%20user%2Fallergy.write%20user%2Fappointment.read%20user%2Fappointment.write%20user%2Fdental_issue.read%20user%2Fdental_issue.write%20user%2Fdocument.read%20user%2Fdocument.write%20user%2Fdrug.read%20user%2Fencounter.read%20user%2Fencounter.write%20user%2Ffacility.read%20user%2Ffacility.write%20user%2Fimmunization.read%20user%2Finsurance.read%20user%2Finsurance.write%20user%2Finsurance_company.read%20user%2Finsurance_company.write%20user%2Finsurance_type.read%20user%2Flist.read%20user%2Fmedical_problem.read%20user%2Fmedical_problem.write%20user%2Fmedication.read%20user%2Fmedication.write%20user%2Fmessage.write%20user%2Fpatient.read%20user%2Fpatient.write%20user%2Fpractitioner.read%20user%2Fpractitioner.write%20user%2Fprescription.read%20user%2Fprocedure.read%20user%2Fsoap_note.read%20user%2Fsoap_note.write%20user%2Fsurgery.read%20user%2Fsurgery.write%20user%2Ftransaction.read%20user%2Ftransaction.write%20user%2Fvital.read%20user%2Fvital.write%20user%2FAllergyIntolerance.read%20user%2FCareTeam.read%20user%2FCondition.read%20user%2FCoverage.read%20user%2FEncounter.read%20user%2FImmunization.read%20user%2FLocation.read%20user%2FMedication.read%20user%2FMedicationRequest.read%20user%2FObservation.read%20user%2FOrganization.read%20user%2FOrganization.write%20user%2FPatient.read%20user%2FPatient.write%20user%2FPractitioner.read%20user%2FPractitioner.write%20user%2FPractitionerRole.read%20user%2FProcedure.read
314 &user_role=users
315 &username=admin
316 &password=pass'
319 Example for `patient` role:
320 ```sh
321 curl -X POST -k -H 'Content-Type: application/x-www-form-urlencoded'
322 -i 'https://localhost:9300/oauth2/default/token'
323 --data 'grant_type=password
324 &client_id=LnjqojEEjFYe5j2Jp9m9UnmuxOnMg4VodEJj3yE8_OA
325 &scope=openid%20offline_access%20api%3Aport%20api%3Afhir%20patient%2Fencounter.read%20patient%2Fpatient.read%20patient%2FAllergyIntolerance.read%20patient%2FCareTeam.read%20patient%2FCondition.read%20patient%2FCoverage.read%20patient%2FEncounter.read%20patient%2FImmunization.read%20patient%2FMedication.read%20patient%2FMedicationRequest.read%20patient%2FObservation.read%20patient%2FPatient.read%20patient%2FProcedure.read
326 &user_role=patient
327 &username=Phil1
328 &password=phil
329 &email=heya@invalid.email.com'
332 Response:
334 ```json
336   "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJrYn...",
337   "token_type": "Bearer",
338   "expires_in": 3599,
339   "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJrYnl1RkRp...",
340   "refresh_token": "def5020017b484b0add020bf3491a8a537fa04eda12..."
344 ### Client Credentials Grant
346 This is an advanced grant that uses JSON Web Key Sets(JWKS) to authenticate and identify the client.  This credential grant is
347 required to be used for access to any **system/\*.$export** scopes.  API clients must register either web accessible JWKS URI that hosts
348 a RSA384 compatible key, or provide their JWKS as part of the registration. Client Credentials Grant access tokens are short
349 lived and valid for only 1 minute and no refresh token is issued.  Tokens are requested at `/oauth2/default/token`
350 To walk you through how to do this process you can follow [this guide created by HL7](https://hl7.org/fhir/uv/bulkdata/authorization/index.html).
352 ### Logout
354 A grant (both Authorization Code and Password grants) can be logged out (ie. removed) by url of `oauth2/<site>/logout?id_token_hint=<id_token>`; an example full path would be `https://localhost:9300/oauth2/default/logout?id_token_hint=<id_token>`. Optional: `post_logout_redirect_uri` and `state` parameters can also be sent; note that `post_logout_redirect_uris` also needs to be set during registration for it to work.
356 ## OpenID Connect
357 - The OpenEMR OpenID Connect discover endpoint is `https://{openmr_host}/oauth2/{site}/.well-known/openid-configuration` as the base URI. An example on the OpenEMR easy-dev docker with the 'default' site installation would be: https://localhost:9300/oauth2/default/.well-known/openid-configuration
358 - A sample response is the following:
359     ```json
360     {
361        "issuer": "https://localhost:9300/oauth2/default",
362        "authorization_endpoint": "https://localhost:9300/oauth2/default/authorize",
363        "token_endpoint": "https://localhost:9300/oauth2/default/token",
364        "jwks_uri": "https://localhost:9300/oauth2/default/jwk",
365        "userinfo_endpoint": "https://localhost:9300/oauth2/default/userinfo",
366        "registration_endpoint": "https://localhost:9300/oauth2/default/registration",
367        "end_session_endpoint": "https://localhost:9300/oauth2/default/logout",
368        "introspection_endpoint": "https://localhost:9300/oauth2/default/introspect",
369        "scopes_supported": [
370          "openid",
371          "fhirUser",
372          "online_access",
373          "offline_access",
374          "launch",
375          "launch\/patient",
376          "api:oemr",
377          "api:fhir",
378          "api:port"
379        ]
380     }
381    ```
382 - The standard site used is **default**
383 - OpenEMR supports token revocation.  It is recommended that clients use the OpenID Connect **introspection_endpoint** retrieved from the discovery endpoint to verify a token is active before assuming the token is active.
385 ### More Details
387 The forum thread that detailed development of Authorization and where questions and issues are addressed is here: https://community.open-emr.org/t/v6-authorization-and-api-changes-afoot/15450
389 More specific development api topics are discussed and described on the above forum thread (such as introspection).
391 ## Standard API Documentation
393 The Standard API is documented via Swagger. Can see this documentation (and can test it) by going to the `swagger` directory in your OpenEMR installation. The Standard API is documented there in the `standard` section. Can also see (and test) this in the online demos at https://www.open-emr.org/wiki/index.php/Development_Demo#Daily_Build_Development_Demos (clicking on the `API (Swagger) User Interface` link for the demo will take you there).  Make sure to set your client api registration's redirect_uris to be `<OpenEMR base URI>/swagger/oauth2-redirect.html`.
395 OpenEMR standard endpoints Use `https://localhost:9300/apis/default/api as base URI.`
397 Note that the `default` component can be changed to the name of the site when using OpenEMR's multisite feature.
399 _Example:_ `https://localhost:9300/apis/default/api/patient` returns a resource of all Patients.
401 The Bearer token is required for each OpenEMR API request, and is conveyed using an Authorization header. Note that the Bearer token is the access_token that is obtained in the above [Authorization](API_README.md#authorization) section.
403 Request:
405 ```sh
406 curl -X GET 'https://localhost:9300/apis/default/api/patient/1/medical_problem' \
407   -H 'Authorization: Bearer eyJ0b2tlbiI6IjAwNmZ4TWpsNWhsZmNPelZicXBEdEZVUlNPQUY5KzdzR1Jjejc4WGZyeGFjUjY2QlhaaEs4eThkU3cxbTd5VXFBeTVyeEZpck9mVzBQNWc5dUlidERLZ0trUElCME5wRDVtTVk5bE9WaE5DTHF5RnRnT0Q0OHVuaHRvbXZ6OTEyNmZGUmVPUllSYVJORGoyZTkzTDA5OWZSb0ZRVGViTUtWUFd4ZW5cL1piSzhIWFpJZUxsV3VNcUdjQXR5dmlLQXRXNDAiLCJzaXRlX2lkIjoiZGVmYXVsdCIsImFwaSI6Im9lbXIifQ=='
410 ## Patient Portal API Documentation
412 The Patient Portal API is documented via Swagger. Can see this documentation (and can test it) by going to the `swagger` directory in your OpenEMR installation. The Patient Portal API is documented there in the `standard-patient` section. Can also see (and test) this in the online demos at https://www.open-emr.org/wiki/index.php/Development_Demo#Daily_Build_Development_Demos (clicking on the `API (Swagger) User Interface` link for the demo will take you there). Make sure to set your client api registration's redirect_uris to be `<OpenEMR base URI>/swagger/oauth2-redirect.html`.
414 This is under development and is considered EXPERIMENTAL.
416 Enable the Patient Portal API service (/portal/ endpoints) in OpenEMR menu: Administration->Globals->Connectors->"Enable OpenEMR Patient Portal REST API (EXPERIMENTAL)"
418 OpenEMR patient portal endpoints Use `https://localhost:9300/apis/default/portal as base URI.`
420 Note that the `default` component can be changed to the name of the site when using OpenEMR's multisite feature.
422 _Example:_ `https://localhost:9300/apis/default/portal/patient` returns a resource of the patient.
424 The Bearer token is required for each OpenEMR API request, and is conveyed using an Authorization header. Note that the Bearer token is the access_token that is obtained in the above [Authorization](API_README.md#authorization) section.
426 Request:
428 ```sh
429 curl -X GET 'https://localhost:9300/apis/default/portal/patient' \
430   -H 'Authorization: Bearer eyJ0b2tlbiI6IjAwNmZ4TWpsNWhsZmNPelZicXBEdEZVUlNPQUY5KzdzR1Jjejc4WGZyeGFjUjY2QlhaaEs4eThkU3cxbTd5VXFBeTVyeEZpck9mVzBQNWc5dUlidERLZ0trUElCME5wRDVtTVk5bE9WaE5DTHF5RnRnT0Q0OHVuaHRvbXZ6OTEyNmZGUmVPUllSYVJORGoyZTkzTDA5OWZSb0ZRVGViTUtWUFd4ZW5cL1piSzhIWFpJZUxsV3VNcUdjQXR5dmlLQXRXNDAiLCJzaXRlX2lkIjoiZGVmYXVsdCIsImFwaSI6Im9lbXIifQ=='
433 ## Security
434 - OpenEMR adminstrators / installers should ensure that the API is protected using an end to end encryption protocol such as TLS
435 - Password Grant SHOULD be turned off for any kind of production use as it has a number of security problems
436 - Setting the Admin -> Globals -> OAuth2 App Manual Approval Settings to be 'Manual Approval' prevents any OAuth2 application from accessing the API without manual approval from an administrator.  This is the most secure setting.  However, in the USA jurisdiction that must comply with CEHRT rules for ONC 2015 Cures Update, patient standalone apps must be approved within 48 hours of a patient requesting access in order to avoid pentalities under the Information Blocking Provisions from ONC.  EHR administrators are not allowed to vet a patient's choice of an app as long as the app complies with OpenEMR's OAuth2 security requirements.  If an app requests user/* or system/* scopes, administrators can vet an application and request additional information / security on an app by app basis.  Leaving the setting at the default will auto-approve any patient standalone app.
437 - Public apps (ones that can't securely store a secret) MUST implement the PKCE standard specified in [RFC 7636](https://www.rfc-editor.org/rfc/rfc7636).  Confidential apps are still highly encouraged to implement PKCE to mitigate forms of MITM attacks such as multiple native app devices registering for the same custom url scheme used as the OAUTH2 redirect_uri in the authorization_code grant.
439 ## For Developers
441 -   For business logic, make or use the services [here](src/Services)
442 -   For controller logic, make or use the classes [here](src/RestControllers)
443 -   For routing declarations, use the class [here](_rest_routes.inc.php).
445 REST API endpoints are defined in the [primary routes file](_rest_routes.inc.php). The routes file maps an external, addressable
446 endpoint to the OpenEMR controller which handles the request, and also handles the JSON data conversions.
448 ```php
449 "POST /api/patient" => function () {
450     RestConfig::authorization_check("patients", "demo");
451     $data = (array) (json_decode(file_get_contents("php://input")));
452     $return = (new PatientRestController())->post($data);
453     RestConfig::apiLog($return, $data);
454     return $return;
458 At a high level, the request processing flow consists of the following steps:
461 JSON Request -> Controller Component -> Validation -> Service Component -> Database
464 The logical response flow begins with the database result:
467 Database Result -> Service Component -> Controller Component -> RequestControllerHelper -> JSON Response
470 The [RequestControllerHelper class](./src/RestControllers/RestControllerHelper.php) evaluates the Service Component's
471 result and maps it to a http response code and response payload. Existing APIs should be updated to utilize the
472 `handleProcessingResult` method as it supports the [Validator](./src/Validators/BaseValidator.php) components.
474 The [PatientRestController](./src/RestControllers/PatientRestController.php) may be used as a reference to see how APIs are
475 integrated with `RequestControllerHelper::handleProcessingResult` and the `Validator` components.
477 Finally, APIs which are integrated with the new `handleProcessingResult` method utilize a common response format.
479 ```json
481     "validationErrors": [],
482     "internalErrors": [],
483     "data": < data payload >
487 -   `validationErrors` contain "client based" data validation errors
488 -   `internalErrors` contain server related errors
489 -   `data` is the response payload, represented as an object/`{}` for single results or an array/`[]` for multiple results