drchrono · Authentication Profile

Drchrono Authentication

Authentication

DrChrono runs two independent OAuth 2.0 estates that share no tokens, no scopes and no discovery surface. The proprietary REST v4 API authenticates against app.drchrono.com with a DrChrono-specific scope vocabulary and a hard 48-hour access-token lifetime. The ONC-certified SMART on FHIR R4 API authenticates against a separate EverHealth-hosted authorization server with SMART scopes, PKCE and OIDC. A token from one is not valid against the other.

drchrono secures its APIs with oauth2 across 4 declared security schemes, as derived from its OpenAPI definitions. OAuth 2.0 is offered via the authorizationCode, clientCredentials, refreshToken, implicit, and deviceCode flow(s).

EHRElectronic Health RecordsHealthcareMedical RecordsPractice ManagementHIPAAAppointmentsBillingPrescriptionsLab IntegrationFHIRSMART on FHIRUSCDIInteroperabilityWebhookAuthenticationONC CertifiedTelehealthRevenue Cycle Management
Methods: oauth2 Schemes: 4 OAuth flows: authorizationCode, clientCredentials, refreshToken, implicit, deviceCode API key in:

Security Schemes

drchrono_oauth2 oauth2
· flows: authorizationCode
drchrono_smart_fhir oauth2
· flows: authorizationCode, clientCredentials, refreshToken, implicit, deviceCode
drchrono_iframe_jwt jwt
drchrono_webhook_secret shared secret

Source

Authentication Profile

Raw ↑
generated: '2026-08-14'
method: searched
source: https://app.drchrono.com/api-docs/
docs: https://app.drchrono.com/api-docs/tutorial/
name: drchrono Authentication
description: >-
  DrChrono runs two independent OAuth 2.0 estates that share no tokens, no scopes and no discovery
  surface. The proprietary REST v4 API authenticates against app.drchrono.com with a DrChrono-specific
  scope vocabulary and a hard 48-hour access-token lifetime. The ONC-certified SMART on FHIR R4 API
  authenticates against a separate EverHealth-hosted authorization server with SMART scopes, PKCE and
  OIDC. A token from one is not valid against the other.

summary:
  types: [oauth2]
  oauth2_flows: [authorizationCode, clientCredentials, refreshToken, implicit, deviceCode]
  api_keys: false
  basic_auth: false
  mutual_tls: false
  openid_connect: true
  openid_connect_scope: FHIR surface only

schemes:
  - name: drchrono_oauth2
    surface: REST v4 API (app.drchrono.com)
    type: oauth2
    declared_in: openapi/_original/drchrono-rest-api-openapi-schema.json
    flows:
      - flow: authorizationCode
        authorizationUrl: https://app.drchrono.com/o/authorize/
        tokenUrl: https://app.drchrono.com/o/token/
        revocationUrl: https://app.drchrono.com/o/revoke_token
        scopes: 22
        scope_artifact: scopes/drchrono-scopes.yml
    token:
      transport: 'Authorization: Bearer <access_token>'
      access_token_lifetime_hours: 48
      refresh: refresh_token grant against the same token endpoint, omitting redirect_uri
      authorization_code_lifetime: >-
        Very short. DrChrono warns the code "expires extremely quickly" and that the exchange must
        happen before the redirect page is rendered to the user.
      rotation: not documented
    client_registration:
      self_serve: true
      console: https://app.drchrono.com/api-management/
      path_in_app: Account > Other Settings > API
      requires: application name, one or more redirect URIs
      issues: client id, client secret
      note: A free DrChrono account is enough to create an API application.
    scope_default_hazard: >-
      Omitting the scope parameter on the authorize call requests ALL scopes. DrChrono's own
      documentation advises requesting only what is needed; the default is maximal, not minimal.
    permission_gate:
      description: >-
        Scopes alone do not authorise access. DrChrono enforces a second, independent gate: a primary
        user must grant the corresponding permission to the user inside the DrChrono web app. A token
        carrying the correct scope still returns 403 when the in-app permission is absent, and this is
        the single most common integration failure on this API.
      example: >-
        The share_communications permission controls whether /api/messages and /api/lab_results share
        practice communication data over the API; it is editable only by DrChrono employees on request
        to api@drchrono.com.
    discovery:
      oauth_authorization_server: false
      openid_configuration: false
      note: >-
        No RFC 8414 or OIDC metadata document is published for this authorization server.
        https://app.drchrono.com/.well-known/oauth-authorization-server returned 404 on 2026-08-14.
        Endpoints exist only in prose.
    sources:
      - https://app.drchrono.com/api-docs/
      - https://app.drchrono.com/api-docs/tutorial/
      - openapi/_original/drchrono-rest-api-openapi-schema.json

  - name: drchrono_smart_fhir
    surface: SMART on FHIR R4 API (drchrono-fhirpresentation.everhealthsoftware.com)
    type: oauth2
    openid_connect: true
    issuer: https://drchrono-fhir.everhealthsoftware.com/core
    declared_in: well-known/drchrono-fhir-smart-configuration.json
    flows:
      - flow: authorizationCode
        authorizationUrl: https://drchrono-fhir.everhealthsoftware.com/core/connect/authorize
        tokenUrl: https://drchrono-fhir.everhealthsoftware.com/core/connect/token
        pkce: required in practice (S256 is the only advertised challenge method)
        aud_parameter: 'the FHIR base URL must be passed as aud on the authorize call'
      - flow: clientCredentials
        tokenUrl: https://drchrono-fhir.everhealthsoftware.com/core/connect/token
        client_assertion: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'
        used_for: FHIR Bulk Data Export with scope system/*.read
      - flow: refreshToken
      - flow: implicit
      - flow: deviceCode
        grant: 'urn:ietf:params:oauth:grant-type:device_code'
    endpoints:
      introspection: https://drchrono-fhir.everhealthsoftware.com/core/connect/introspect
      revocation: https://drchrono-fhir.everhealthsoftware.com/core/connect/revocation
      registration: https://drchrono-fhir.everhealthsoftware.com/core/permissions
    client_auth_methods: [client_secret_basic, client_secret_post, private_key_jwt]
    scopes: 233
    scope_artifact: scopes/drchrono-fhir-smart-scopes.yml
    client_registration:
      self_serve: false
      dynamic_client_registration: false
      note: >-
        The registration endpoint is a permissions console. DrChrono states only EHR vendor admins can
        add a client app, supplying application URL, redirect URL, logout URL, scope list, application
        name and OAuth flow.
    discovery:
      smart_configuration: https://drchrono-fhirpresentation.everhealthsoftware.com/fhir/drchrono/498711/r4/.well-known/smart-configuration
      openid_configuration: https://drchrono-fhir.everhealthsoftware.com/core/.well-known/openid-configuration
      status: both returned 200 on 2026-08-14 and are saved verbatim under well-known/
    sources:
      - well-known/drchrono-fhir-smart-configuration.json
      - well-known/drchrono-fhir-openid-configuration.json
      - https://drchrono-fhirpresentation.everhealthsoftware.com/drchrono/498711/r4/Home/ApiDocumentation

  - name: drchrono_iframe_jwt
    surface: Embedded iframe applications inside the DrChrono patient chart and clinical note
    type: jwt
    algorithm: HS256
    key: the API application's client_secret
    claims: [doctor_id, patient_id, practice_id, iat]
    description: >-
      DrChrono appends a signed JWT to the iframe src when rendering a third-party application inside
      the patient chart or clinical note page. The JWT signs the context parameters so the embedding
      application can verify it is being loaded by an authorised DrChrono user. Because same-origin
      policy blocks postMessage-free data exchange, the JWT is the only trusted context channel.
    guidance: >-
      Validate the JWT with a vetted library and use ONLY the claims extracted from it — never the raw
      query parameters. DrChrono's own example allows 60 seconds of clock drift.
    source: https://app.drchrono.com/api-docs/

  - name: drchrono_webhook_secret
    surface: Outbound webhook deliveries
    type: shared secret
    header: X-drchrono-signature
    verification_handshake: HMAC-SHA256 hex digest of the msg query parameter, keyed by the webhook secret token
    description: >-
      Webhook deliveries carry the shared secret in a header rather than an HMAC of the request body,
      so the header authenticates the sender but attests nothing about payload integrity. A separate
      HMAC-SHA256 challenge/response is used once at webhook creation and whenever the callback URL
      changes.
    source: https://app.drchrono.com/api-docs/

findings:
  - >-
    Neither DrChrono OAuth surface publishes RFC 8414 authorization-server metadata for the REST API;
    only the FHIR estate is discoverable.
  - >-
    The 48-hour access token is short for a background integration and there is no client-credentials
    flow on the REST API — every REST integration is bound to a human user's authorization and must
    keep a refresh token alive indefinitely.
  - >-
    PKCE is available on the FHIR surface and absent from the REST surface's documentation.
  - >-
    The scope/permission double gate is the defining characteristic of DrChrono auth and is invisible
    in the OpenAPI. It is documented in prose only.