Authentication & Security
The ChartChat server handles all authentication through Medplum's OAuth2 / PKCE-based auth system. This page covers how each auth method works, what configuration is required, and important security requirements.
Auth methods supported​
| Method | Endpoint | Used by |
|---|---|---|
| Email + Password | POST /auth/login | Member Portal sign in |
| Google OAuth | POST /auth/google | Member Portal Google Sign-In button |
| External / SSO (Microsoft, Epic, etc.) | GET /auth/external | Member Portal Microsoft SSO, EHR OAuth |
| MFA (TOTP) | POST /auth/mfa/verify | Member Portal after password login |
| Patient registration | POST /auth/register | Member Portal sign up |
| New patient via invite | POST /auth/newpatient | Admin Portal invite patient flow |
External auth providers (/auth/external)​
The /auth/external endpoint handles all OAuth2 redirects from external identity providers — Microsoft Azure AD, Epic MyChart, Healow, MEDITECH, and any other SMART on FHIR provider.
Required setup — ClientApplication configuration​
For /auth/external to work, you must configure the identity provider details inside the ClientApplication resource in the Admin Portal. Without this, the server does not know where to redirect users or how to exchange the authorization code.
Steps:
- Open the Admin Portal
- Go to the FHIR resource browser →
ClientApplication - Open the
ClientApplicationused by the Member Portal - Edit the resource and add an
identityProviderblock:
{
"identityProvider": {
"authorizeUrl": "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize",
"tokenUrl": "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token",
"clientId": "your-microsoft-client-id",
"clientSecret": "your-microsoft-client-secret",
"useSubject": true
}
}
How the server resolves the identity provider:
- Looks up the
ClientApplicationby theclientIdin the request. - If
client.identityProvideris set → uses it. - If not, falls back to the domain-level
identityProviderconfig. - If neither is set → returns an error.
Each external provider (Microsoft, Epic per hospital, etc.) should have its own
ClientApplicationwith its ownidentityProviderconfiguration, or use theSSOIntegrationresource configured via the Admin Portal's SSO Integrations page.
defaultPatientAccessPolicy — required for patient registration​
The project must have a defaultPatientAccessPolicy set for any flow that creates a new patient account. Without it, the server returns a 400 error and blocks the operation.
| Scenario | Server file | Error if missing |
|---|---|---|
Patient self-registration (POST /auth/register) | patientregister.ts | 400 - Project does not allow open registration |
New patient creation via invite (POST /auth/newpatient) | newpatient.ts | 400 - Project does not allow open registration |
| Open registration check | routes.ts | 400 - Project does not allow open registration |
What it does​
When a new patient account is created, the server automatically assigns the defaultPatientAccessPolicy to the new ProjectMembership:
const policy = await systemRepo.readReference(project.defaultPatientAccessPolicy);
await createProjectMembership(systemRepo, user, project, profile, {
accessPolicy: createReference(policy),
});
This controls what FHIR resources the new patient can read and write.
How to set it​
- Open the Admin Portal
- Go to Admin → Project Details
- Set the
defaultPatientAccessPolicyfield to reference your patientAccessPolicyresource
Does /auth/google or /auth/external require it?​
- Existing users signing in via Google or Microsoft →
defaultPatientAccessPolicyis not required. The server finds their existingProjectMembershipand logs them in. - First-time sign-in via SSO where a new patient account is created →
defaultPatientAccessPolicyis required. The server callscreatePatient()internally which checks for it.
MFA (Two-Factor Authentication)​
Patients can enable TOTP-based MFA from the Member Portal Settings page.
Login flow with MFA enabled:
- Patient submits email + password to
POST /auth/login. - Server returns
{ mfaRequired: true, login: "<loginId>" }. - Patient enters the 6-digit code from their authenticator app.
- Client posts
{ login: loginId, token: code }toPOST /auth/mfa/verify. - Server verifies the TOTP code and returns
{ code }to complete the login.
CSRF Protection​
The server uses CSRF tokens to protect state-changing endpoints. The CSRF token is generated per session and validated on every non-GET request.
File: packages/server/src/csrf.ts
Rate Limiting​
API endpoints are rate-limited to prevent brute force attacks and abuse.
File: packages/server/src/ratelimit.ts
Rate limits are applied per IP address. Auth endpoints (/auth/login, /auth/google, etc.) have stricter limits than general API endpoints.
Breach Detection​
ChartChat includes a PHI access breach detection system that monitors for unusual access patterns — such as a single user accessing an abnormally large number of patient records in a short time.
File: packages/server/src/security/
Breach events are logged as AuditEvent resources and are visible in the Admin Portal's Audit Log.