Skip to main content

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​

MethodEndpointUsed by
Email + PasswordPOST /auth/loginMember Portal sign in
Google OAuthPOST /auth/googleMember Portal Google Sign-In button
External / SSO (Microsoft, Epic, etc.)GET /auth/externalMember Portal Microsoft SSO, EHR OAuth
MFA (TOTP)POST /auth/mfa/verifyMember Portal after password login
Patient registrationPOST /auth/registerMember Portal sign up
New patient via invitePOST /auth/newpatientAdmin 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:

  1. Open the Admin Portal
  2. Go to the FHIR resource browser → ClientApplication
  3. Open the ClientApplication used by the Member Portal
  4. Edit the resource and add an identityProvider block:
{
"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:

  1. Looks up the ClientApplication by the clientId in the request.
  2. If client.identityProvider is set → uses it.
  3. If not, falls back to the domain-level identityProvider config.
  4. If neither is set → returns an error.

Each external provider (Microsoft, Epic per hospital, etc.) should have its own ClientApplication with its own identityProvider configuration, or use the SSOIntegration resource 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.

ScenarioServer fileError if missing
Patient self-registration (POST /auth/register)patientregister.ts400 - Project does not allow open registration
New patient creation via invite (POST /auth/newpatient)newpatient.ts400 - Project does not allow open registration
Open registration checkroutes.ts400 - 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​

  1. Open the Admin Portal
  2. Go to Admin → Project Details
  3. Set the defaultPatientAccessPolicy field to reference your patient AccessPolicy resource

Does /auth/google or /auth/external require it?​

  • Existing users signing in via Google or Microsoft → defaultPatientAccessPolicy is not required. The server finds their existing ProjectMembership and logs them in.
  • First-time sign-in via SSO where a new patient account is created → defaultPatientAccessPolicy is required. The server calls createPatient() 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:

  1. Patient submits email + password to POST /auth/login.
  2. Server returns { mfaRequired: true, login: "<loginId>" }.
  3. Patient enters the 6-digit code from their authenticator app.
  4. Client posts { login: loginId, token: code } to POST /auth/mfa/verify.
  5. 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.