oauth2
, jwt
, api
, authentication
, openemr-7.0.3
We’re trying to integrate OpenEMR (v7.0.3 on Google Cloud) using OAuth2 client_credentials
flow with private_key_jwt
authentication. All steps were followed exactly, but we still receive a 400 Bad Request with "invalid_client"
error when exchanging the JWT for a token.
1. Created JWKS and Hosted It Publicly
- Generated RSA key pair
- Hosted JWKS (https: //mkjwk. org/) with
kid
,n
,e
, andalg=RS256
2. Configured Public Key in OpenEMR (Google Cloud VM)
- Added the PEM public key to the trusted keys
3. Registered a Client in OpenEMR Admin Interface
- Confidential client with
private_key_jwt
- Set JWKS URL and public key
- Enabled client
4. Generated JWT Assertion (Programmatically)
- Header included correct
kid
andalg
- Payload had
iss
,sub
,aud
,iat
,exp
- Signed with matching RSA private key
- JWT validated correctly on jwt.io and compiled in https://token.dev/
5. Made Token Request via Postman & Self-Hosted Hoppscotch
POST
to/oauth2/default/token
- Body:
grant_type=client_credentials
client_id=<our-client-id>
client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
client_assertion=<generated JWT>
6. Result:
Always getting:
{
"error": "invalid_client",
"error_description": "Client authentication failed"
}
(Postman)
Checked:
kid
matches- JWT signed correctly
iat/exp
fresh and accurate- JWKS URL is accessible
aud
is the token endpoint- Public key same across JWKS and OpenEMR trusted keys
Need Help With:
- Is there a known bug in v7.0.3 with
private_key_jwt
? - Does OpenEMR require anything non-standard in JWTs?
- Any logs we can check or extra debug steps?
- Are there specific
aud
or formatting issues that could trigger this?
We’re stuck at this final step and would greatly appreciate any guidance.
Thanks in advance!