Vendor notes
How each EHR says no
Each EHR words its failures differently and has its own registration gotchas. smart-doctor adds these hints when it recognises the server. They are possibilities from public sources, not facts about any one installation.
Epic
4 hintsNon-production vs production client ID
invalid_client
Epic issues separate non-production and production client IDs for each app. The public sandbox only accepts the non-production ID, and customer environments only accept the ID that was activated there.
Confirm which client ID you are using and that it matches the environment you are calling.
Source: Epic on FHIR documentation (fhir.epic.com → Documentation → OAuth 2.0): apps get separate non-production and production client IDs.
New key or JWKS change not picked up yet
invalid_clientprivate_key_jwt only
After you upload a key or change the JWKS URL, the change can take time to reach the environment you are calling. Requests can fail with invalid_client until it does.
Wait and retry later. If it persists, re-check the registration (and that the app was synced to that customer environment).
Source: https://chat-archive.fhir.org/stream/179166-implementers/topic/oauth2.20backend.20services.html
redirect_uri on the token request not registered
invalid_clientuser sign-in
Epic answers invalid_client (not invalid_grant) when the redirect_uri sent with the code exchange is not one registered for this client, so a redirect URI difference can look like a bad secret.
Send the identical, registered redirect_uri in the authorization request and the token request.
Source: Observed on the public Epic sandbox (fhir.epic.com), October 2026: bad code + registered redirect_uri → invalid_grant; bad code + unregistered redirect_uri → invalid_client.
App not activated for this organisation
invalid_client
Apps generally need to be enabled by each customer organisation. Perfectly valid credentials are still rejected where the app is not activated.
Ask the organisation’s Epic analysts to confirm the app (your client ID) is activated in that environment.
Source: Epic on FHIR documentation (fhir.epic.com): customer organisations must download/activate an app before its production client ID works there.
Oracle Health (Cerner)
2 hintsSystem account uses a different auth method
invalid_client
Oracle Health system accounts are configured in the developer console with a specific client authentication method. A signed JWT will be rejected if the account is set up for a client secret, and vice versa.
Check the system account configuration and use the matching auth method.
Source: Oracle Health (Cerner) FHIR developer documentation (fhir.cerner.com → Authorization): system accounts and their client authentication.
Tenant in the URL does not match the account
invalid_client
The FHIR base URL contains a tenant identifier. The system account must be authorised for that tenant.
Confirm the tenant ID in your FHIR base and token URLs matches the one your account is provisioned for.
Source: Oracle Health (Cerner) FHIR developer documentation (fhir.cerner.com): service root URLs are tenant-specific.
OpenEMR
2 hintsSystem client not enabled by an administrator
invalid_client
OpenEMR registers new system (backend) clients as disabled until an administrator enables them.
In OpenEMR: Administration → System → API Clients, find your client and enable it.
Source: OpenEMR FHIR_README.md / API_README.md (github.com/openemr/openemr): system clients must be enabled by an administrator.
OpenEMR reports most assertion problems the same way
any error
OpenEMR typically answers assertion problems with a generic "Client authentication failed" message, so the local checks above are the best guide.
Fix any failing local checks first, then check the client’s registered JWKS / jwks_uri.
Source: https://community.open-emr.org/t/401-client-authentication-failed-when-using-jwt-signed-token/24378
athenahealth
1 hintApp configured for a different auth method
invalid_client
Confirm in the developer portal how your app authenticates (client secret vs signed JWT) and which environment (preview vs production) its credentials belong to.
Use the auth method and credentials for the environment you are calling.
Source: athenahealth developer portal documentation (docs.athenahealth.com): separate preview and production environments and credentials.