How to Interoperate with CareEvolution
I've been trying to interoperate with careevoltion using their backend-services.
Spec: http://docs.smarthealthit.org/authorization/backend-services/
This involves creating a JWT (JSON Web Token) that I have been unable to do using %OAuth2.JWT:ObjectToJWT.
I downloaded jwt.pfx and then ran the following openssl commands to create some pem files.
openssl pkcs12 -in jwt.pfx -out file.nokey.pem -nokeys openssl pkcs12 -in jwt.pfx -out file.withkey.pem openssl rsa -in file.withkey.pem -out file.key cat file.nokey.pem file.key > file.combo.pem3
I then ran some node code to create the private portions of the RSA key:
var fs = require('fs'); var rsaPemToJwk = require('rsa-pem-to-jwk'); var pem = fs.readFileSync('file.key'); console.log(pem); var jwk = rsaPemToJwk(pem, {use: 'sig'}, 'private'); console.log(JSON.stringify(jwk)); C:\Users\Paul\Desktop\jwt>node rsa-pem-to-jwk.txt > c:\tmp\priv.txt
I then changed the node code so that it created the public portions of the RSA key.
var jwk = rsaPemToJwk(pem, {use: 'sig'}, 'public'); C:\Users\Paul\Desktop\jwt>node rsa-pem-to-jwk.txt > c:\tmp\public.txt
I then ran the following COS code:
KILL JOSE S JOSE("keyalg")="RSA" S JOSE("sigalg")="RS256" S A=+$H-47117 S B=A*86400 S C=$P($HOROLOG,",",2) S EPOCH=B+C // add 4 minutes S D=60*4 S EPOCH=EPOCH+D set body=##class(%DynamicObject).%New() do body.%Set("iss","JWTClientCredentials","string") do body.%Set("aud","https://fhir.careevolution.com/Master.Adapter1.WebClient/identityserver/connect/token","string") do body.%Set("exp",EPOCH,"string") // 1516032893 do body.%Set("nbf",EPOCH,"string") // 1516032893 do body.%Set("jti","db5ba9b3-602c-4b5f-beb9-4e8d76028c01","string") do body.%Set("sub","07e5a735-a4f7-e711-8136-0a69c1b3225b","string") do body.%Set("user_name","psimon","string") do body.%Set("clientid","JWTClientCredentials","string") // copied from /tmp/priv.txt (node output) s localpriv="{ ""kty"": ""RSA"", ""n"": ""s0hguxNL5Xb6_Fk3u_fnZrUXuRnjj1wIEGXlsnqbu4rptiDYeX9dEQm29eDe5fhXWjrPtU33WA_zz0Y9R5z7EaX4ZlZG7PlFlm5vu3bEu-qeuMp8Xb3hPMyND-87JGrbB1t5i-BgMpjQoelhYT8iqzE1fEtUGYyNn2dhSwIVwqIaRt4ly65oyW9Ea7VL92kmCEgUmIn-lrEfvygfbEL2H-9dW42dAMvEwLCQGM7iX1zuHRAH9Ec9kwnaBb2kfHzoSJXZm5WcuPYJIWZrvu1RbHcZBFff0GwCDTH1bfECmr6c-6BPeeUMw6resnbM4v3dTrbKD64HQbC33x4_Xs3pTQ"", ""e"": ""AQAB"", ""d"": ""FVOizh45hQ5mROaIDsAqsrkQHWDLBR65htnYPScAp4qayqOVnL5d38z8Cru5SDoGiiE83CBuL_eV1S5R09cEttC7f9D7lu0ALijs-avjM0dxoiHUMYKI7KaYkTCwJGDhtTpYdx810k8DYn9UqjDMevjbl_GOC4wAvNmbZUTWOdTDfVXm7D42vcUnh0e7nTYu7qGBRcfRrduzjBZMSddZoz8suWbJlQowUt6-bYOUPixeclML8oOKrtuQ_Y6fI-SNkaM5MrrJku-s1KXiOt5ZGXkpqE-PUQsw1DAzs6MfS6CcuFdYadlBd6sn6bOLNJN3DffDJQGHQUIUefTJ2I_YMQ"", ""p"": ""7CSQiUHeP_C2QBgQEsC_yF0Q1AFHmNEn9ua0lJ20LJSu7zzYCdE6E5X-j-9w37nzdzOClceEI2-2OAvV_Ukh3R78q9_-Mtc9AUk2BunwzfaAdJHl0YT0IpJEI-IluMpOX9RETTK3KXpjOFBefHOeHS0DyWLRXDaAt2k_9c1Q1Lc"", ""q"": ""wlvJ3Ap_i1vxt5q6zRT6JBxstvXLi0hQgHZnchvNluOfhzBTfYTSiK0n6Od-yj1c90iZt97B4XKWfps29xwd6wqS6X-QtG59AvlU0IOH4FSoYvyVy4yqpMSzAjgmhwZRi-API7XWd1KSmkTB8t-XfdxjdnC6kM62MqtsdC-Vhs"", ""dp"": ""WFFomV1AQUvG7fvR7yGV2Nst0wzTeU0olEg-26KL42yMbL-l0S4meXLM7YpQ_evvKfLi8R_YxOQgE6AhnYR_nNLdD29MBDnKADQgd7-BJ5b8_hwfBxihslhgEcef8hf_7glWrkS8ik_S0hoE7KjVRvYyB1zlDob35yD_IfBzPcs"", ""dq"": ""h5_NiIK65eBPGDQczicpNjGvmyyB0LuxkTMOlI3aNMS5-Xg7ioc48q8B_oAr9axERzqeKbSDznJLmiVtgZpZNj62rcGalI3VJlIeYTKnil8I8aoYTWXnXf5bNY2sTV32NQfIkHmMxOSqhqoz4Wia0a9tyfJ_FUG8urMT6dUkPKk"", ""qi"": ""WsLO8yNdoSMF3sYAISKhx_NJ5ua6PISaezUpYk6WgENHfUnwXXiDpDgx8AKae2vRpPaGoHhJkiih5JHTtVWNGUXB0-DItnX0jodM78NT31XefKuE4Pg6nLtrpPlQpRqL6Gj1en2FcVtQ5TblOaFO9dkBoBB-gGWK9dy0WPR5D9w"" }" // copied from /tmp/public.txt (node output) s localpub=" {""kty"":""RSA"",""use"":""sig"",""n"":""ALaMFdNTmzUu1wnMGNmsIkBMJUS4EdMAe2HXpQ-k4aDk94znJuCi9OJnJQU4lm4nqgEWdzMVVQMlqZ3ihlXx5vpFzmb4m4EkAcmK0ULVCLL9QRqvuwbOjeXW8pJlcH-EAQKnkMzF6GbtmmDubK46bx2GaQh8rLYAfLvoIwXfyrXIday2VdRNz_3yGzLoxr5QxcFml46479mY3xXwmTSMvVNHEN4F1xPnsLQoNPH3guA104dm8S-f2z_vczHBdSrgiJibesdOP3ugYlxJvDDT3WSf3WW7cjAn8M3vZmCNTPWe6JEewsc6cDBiFWn9UUomulFUV_uucTsV_NXMd8nQ_Hs"",""e"":""AQAB""}" SET ST=##class(%OAuth2.JWT).ObjectToJWT(.JOSE,.body,localpriv,localpub,.JWT)
If you run the above code in a terminal session - it does *not* work:
USER>d $system.OBJ.DisplayError(ST) ERROR #5002: Cache error: <INVALID OREF>zGetJWK+2^%OAuth2.JWT.1
Killing JOSE and re-running the code works ... however, the JWT is invalid since I cannot get the POST that contains the JWT to successfully return an access_token?
USER>K JOSE USER>SET ST=##class(%OAuth2.JWT).ObjectToJWT(.JOSE,.body,localpriv,localpub,.JWT) USER>ZW JWT JWT="eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJpc3MiOiJodHRwczovL2ZoaXIuY2FyZWV2b2x1dGlvbi5jb20vTWFzdGVyLkFkYXB0ZXIxLldlYkNsaWVudC8iLCJhdWQiOiJodHRwczovL2ZoaXIuY2FyZWV2b2x1dGlvbi5jb20vTWFzdGVyLkFkYXB0ZXIxLldlYkNsaWVudC8iLCJleHAiOiIxNTE2MTIxNjA5IiwibmJmIjoiMTUxNjEyMTYwOSIsImp0aSI6ImRiNWJhOWIzLTYwMmMtNGI1Zi1iZWI5LTRlOGQ3NjAyOGMwMSIsInN1YiI6IjA3ZTVhNzM1LWE0ZjctZTcxMS04MTM2LTBhNjljMWIzMjI1YiIsInVzZXJfbmFtZSI6InBzaW1vbiIsImNsaWVudGlkIjoiT0F1dGhUZXN0In0."
So, can anyone please tell me what I'm doing wrong here?
To summarise what I'm trying to do is use the pfx cert to sign the JWT and then use that JWT to get hold of an access_token.
The attached C# code will apparently create a JWT that will work with careevolutions back-end services - but so far I've been unable to compile the code in VS-2017.
Finally, can Cache can be configured to support back-end services (similar to the above).
Spec: http://docs.smarthealthit.org/authorization/backend-services/
Thanks,
-- Paul.
{
Set arr=JWKS.keys ;line +1
Set iter=arr.%GetIterator() ;line +2
But there is no array keys and no %DynamicArray object found.
so it fails on %GetIterator().
my guess {"keys":[ .... ]} could be the solution.
w localpub
Thanks very much Robert - that's got me much further!
Script-1 (JWTToObject) creates an object from a valid JWT.
Script-2 (ObjectToJWT) contains Robert's fixes to localpub and localpriv.
Script-1:
ERROR #8897: No public key found for alg: RS256 (kid:)
Script-2:
ERROR #8896: No private key found for alg: RS256
So it seems to me as though its the node code that produces the private and public portions of the RSA key that's used in the localpub and localprov variables that's at fault?
Script-1.
s localpriv="{""keys"":[{""kty"":""RSA"",""use"":""sig"",""n"":""ALaMFdNTmzUu1wnMGNmsIkBMJUS4EdMAe2HXpQ-k4aDk94znJuCi9OJnJQU4lm4nqgEWdzMVVQMlqZ3ihlXx5vpFzmb4m4EkAcmK0ULVCLL9QRqvuwbOjeXW8pJlcH-EAQKnkMzF6GbtmmDubK46bx2GaQh8rLYAfLvoIwXfyrXIday2VdRNz_3yGzLoxr5QxcFml46479mY3xXwmTSMvVNHEN4F1xPnsLQoNPH3guA104dm8S-f2z_vczHBdSrgiJibesdOP3ugYlxJvDDT3WSf3WW7cjAn8M3vZmCNTPWe6JEewsc6cDBiFWn9UUomulFUV_uucTsV_NXMd8nQ_Hs"",""e"":""AQAB"",""d"":""WSQxKEAkg6T651LeM7VmCGXmsRb9xT7wAUhv1yLZ91q4M_tQtdN9p-1cW59VfjcqQlu5G53oJKBIosvSc7er5j0eXJQ8Q6TUppl-NJeZJuaa2zBDMUC-dCUx0SFt_Sb141j2Ubi3E0Ql5f2n3rC0QAO52KYhJMM6Jfxm1eCBuaB0STT9LE-APh0K_wDuyEOFJD52pVOKuUy_v_vDaK4ssfcz-Yq_V1R9H1reu2bHdgMKEYZhkM4d4faVa52pQJvu0M-sm892RYNh34szLLDaKHPmgZgTdtuppZmo0QYuUeFS2fy461GGfQh92dSIgl7H8Gyz6RC07PPwUTaIphLgcQ"",""p"":""APX_qgTRt5bzWb_Xch0hyMgHbMqjfKfavX6AbUv1-Yabn9_Q9XyFx3h7ymDAI2ilTmwjKpdi80izifuKFPV0z6EnLIbebdVGb3MeYBBRmBlx3pfSnx7RI9OAscRm_2xV0j21pP5mknj86VR4MHwmF4BeU-6U-TopwGYldnvyNuVD"",""q"":""AL34BdumlQCkSlr0-kq7E_NksOFTn8qf4tUKDMQFkVbC4oXD33qwAxUtPVfePYJ6XbAqCaB2oPO5ASNC4_-sTCav7Xk6s0xnG_clTGqXS8Xr8Gtwa9Z2oPvUrHFn6XEtnPAi54R-xxmqVSyIKLF5FMiKzmXRw9BWCHETO1bgdfxp"",""dp"":""ALRaLJw75Q2WfEZZ_h-9lSaRywEFu26UwDjujzMRs08s6Zl96XzR19xNZaJpO4yNJWHCpoc21IaImrEAGz2Z1l-gCNUYXg3vBeawbl2IdKqzAS7uDBrb2hhGUg5cNQeIJAt6EO0y5lAtnCOBuopKoxBKF97i-ZXa5mP9M1DL09Nh"",""dq"":""RGTGXyVjYd7EcmjesAcYkLmAwS8lSYM03HSI0g4bHHx_p580l2xFP9uQyVDXHmHF10XbP21WV0kVMsfDZGp45DjUq5_Jq8k3lUxVbc7Y1gIzBcts18LQBLq19wJtVnUQmphGeDpYnlHn5meDFxo7tFPdKWVTNW-0DFnbNFUNxXk"",""qi"":""AN40QpNLLrSHeiHJ_dLobYjX3TGs1BkdH2qu3lt6TlTtSBEjcwg0g_xxkieM-cPpfOCH0NTBfTZM9TTp4u4ncAbWlaw2Ny4VOKSk1AGVnqxzc3KPdvzng244cYq0YGu1UZyU8Oe8m4MrVyxLy0PD1gG3n6fx93o9QBDm2I2QGou1""}]}"
s localpub="{""keys"":[{""kty"":""RSA"",""use"":""sig"",""n"":""ALaMFdNTmzUu1wnMGNmsIkBMJUS4EdMAe2HXpQ-k4aDk94znJuCi9OJnJQU4lm4nqgEWdzMVVQMlqZ3ihlXx5vpFzmb4m4EkAcmK0ULVCLL9QRqvuwbOjeXW8pJlcH-EAQKnkMzF6GbtmmDubK46bx2GaQh8rLYAfLvoIwXfyrXIday2VdRNz_3yGzLoxr5QxcFml46479mY3xXwmTSMvVNHEN4F1xPnsLQoNPH3guA104dm8S-f2z_vczHBdSrgiJibesdOP3ugYlxJvDDT3WSf3WW7cjAn8M3vZmCNTPWe6JEewsc6cDBiFWn9UUomulFUV_uucTsV_NXMd8nQ_Hs"",""e"":""AQAB""}]}"
S JWT="eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IlptTHktQndhUmFjVlBkdDF5Q0syWno1dWVpayJ9.eyJzdWIiOiJKV1RDbGllbnRDcmVkZW50aWFscyIsImp0aSI6IjNhNDk3YTk2LWNhNDgtNDVkNy1iMzRhLTMxZjVmOTNjODNmMyIsImlzcyI6IkpXVENsaWVudENyZWRlbnRpYWxzIiwiYXVkIjoiaHR0cHM6Ly9maGlyLmNhcmVldm9sdXRpb24uY29tL01hc3Rlci5BZGFwdGVyMS5XZWJDbGllbnQvaWRlbnRpdHlzZXJ2ZXIvY29ubmVjdC90b2tlbiIsImV4cCI6MTUxNjIyODcyMywibmJmIjoxNTE2MjIzMzIzfQ.hHnIXYvYdZ2p-WLuFQfeIQ9xfQqcdqzUh1_JT7s6T6yIpEE3JyBeBDKtLFKulFOoGU9cPiCrYGz0iwkmR2b3I_Q9KRSs1JvPjsZCeWQ9ocpKxK0WECqw4sYuvVVFxjer39BRp0YQLLcYgwST86KW_pPeV_ssLGX9G4iJNdy5JFsFO4w19HH_1MM8Aa_FUyimtawuMky9mfwtAzJ4GiP14FsfrafeRIAJsw693z_l9KhCNC-v8vJ_b4_iDREa3c6dCz5GEtANiv9phfzPUL2x7CHMHu-lENBvVNDtl0-Gt0HCD6RFf7NJeH7oYeKR2NpcCT93gCQhX32EMLr5eFJeBw"
K JOSE SET ST=##class(%OAuth2.JWT).JWTToObject(JWT,localpriv,localpub,.JOSE,.Body)
d $system.OBJ.DisplayError(ST)
ERROR #8897: No public key found for alg: RS256 (kid:).
Script-2.
KILL JOSE
S JOSE("sigalg")="RS256"
S A=+$H-47117 // (47117 = 01/01/1970)
// (60*60)*24 (total number of secs in a day)
S B=A*86400
S C=$P($HOROLOG,",",2)
S EPOCH=B+C
// add 4 minutes
S D=60*4
S EPOCH=EPOCH+D
set body=##class(%DynamicObject).%New()
do body.%Set("sub","JWTClientCredentials","string")
do body.%Set("jti","3a497a96-ca48-45d7-b34a-31f5f93c83f3","string")
do body.%Set("iss","JWTClientCredentials","string")
do body.%Set("aud","https://fhir.careevolution.com/Master.Adapter1.WebClient/identityserver/...","string")
do body.%Set("exp",EPOCH,"string")
do body.%Set("nbf",EPOCH,"string")
s localpriv="{""keys"":[{""kty"":""RSA"",""use"":""sig"",""n"":""ALaMFdNTmzUu1wnMGNmsIkBMJUS4EdMAe2HXpQ-k4aDk94znJuCi9OJnJQU4lm4nqgEWdzMVVQMlqZ3ihlXx5vpFzmb4m4EkAcmK0ULVCLL9QRqvuwbOjeXW8pJlcH-EAQKnkMzF6GbtmmDubK46bx2GaQh8rLYAfLvoIwXfyrXIday2VdRNz_3yGzLoxr5QxcFml46479mY3xXwmTSMvVNHEN4F1xPnsLQoNPH3guA104dm8S-f2z_vczHBdSrgiJibesdOP3ugYlxJvDDT3WSf3WW7cjAn8M3vZmCNTPWe6JEewsc6cDBiFWn9UUomulFUV_uucTsV_NXMd8nQ_Hs"",""e"":""AQAB"",""d"":""WSQxKEAkg6T651LeM7VmCGXmsRb9xT7wAUhv1yLZ91q4M_tQtdN9p-1cW59VfjcqQlu5G53oJKBIosvSc7er5j0eXJQ8Q6TUppl-NJeZJuaa2zBDMUC-dCUx0SFt_Sb141j2Ubi3E0Ql5f2n3rC0QAO52KYhJMM6Jfxm1eCBuaB0STT9LE-APh0K_wDuyEOFJD52pVOKuUy_v_vDaK4ssfcz-Yq_V1R9H1reu2bHdgMKEYZhkM4d4faVa52pQJvu0M-sm892RYNh34szLLDaKHPmgZgTdtuppZmo0QYuUeFS2fy461GGfQh92dSIgl7H8Gyz6RC07PPwUTaIphLgcQ"",""p"":""APX_qgTRt5bzWb_Xch0hyMgHbMqjfKfavX6AbUv1-Yabn9_Q9XyFx3h7ymDAI2ilTmwjKpdi80izifuKFPV0z6EnLIbebdVGb3MeYBBRmBlx3pfSnx7RI9OAscRm_2xV0j21pP5mknj86VR4MHwmF4BeU-6U-TopwGYldnvyNuVD"",""q"":""AL34BdumlQCkSlr0-kq7E_NksOFTn8qf4tUKDMQFkVbC4oXD33qwAxUtPVfePYJ6XbAqCaB2oPO5ASNC4_-sTCav7Xk6s0xnG_clTGqXS8Xr8Gtwa9Z2oPvUrHFn6XEtnPAi54R-xxmqVSyIKLF5FMiKzmXRw9BWCHETO1bgdfxp"",""dp"":""ALRaLJw75Q2WfEZZ_h-9lSaRywEFu26UwDjujzMRs08s6Zl96XzR19xNZaJpO4yNJWHCpoc21IaImrEAGz2Z1l-gCNUYXg3vBeawbl2IdKqzAS7uDBrb2hhGUg5cNQeIJAt6EO0y5lAtnCOBuopKoxBKF97i-ZXa5mP9M1DL09Nh"",""dq"":""RGTGXyVjYd7EcmjesAcYkLmAwS8lSYM03HSI0g4bHHx_p580l2xFP9uQyVDXHmHF10XbP21WV0kVMsfDZGp45DjUq5_Jq8k3lUxVbc7Y1gIzBcts18LQBLq19wJtVnUQmphGeDpYnlHn5meDFxo7tFPdKWVTNW-0DFnbNFUNxXk"",""qi"":""AN40QpNLLrSHeiHJ_dLobYjX3TGs1BkdH2qu3lt6TlTtSBEjcwg0g_xxkieM-cPpfOCH0NTBfTZM9TTp4u4ncAbWlaw2Ny4VOKSk1AGVnqxzc3KPdvzng244cYq0YGu1UZyU8Oe8m4MrVyxLy0PD1gG3n6fx93o9QBDm2I2QGou1""}]}
"
s localpub="{""keys"":[
{""kty"":""RSA"",""use"":""sig"",""n"":""ALaMFdNTmzUu1wnMGNmsIkBMJUS4EdMAe2HXpQ-k4aDk94znJuCi9OJnJQU4lm4nqgEWdzMVVQMlqZ3ihlXx5vpFzmb4m4EkAcmK0ULVCLL9QRqvuwbOjeXW8pJlcH-EAQKnkMzF6GbtmmDubK46bx2GaQh8rLYAfLvoIwXfyrXIday2VdRNz_3yGzLoxr5QxcFml46479mY3xXwmTSMvVNHEN4F1xPnsLQoNPH3guA104dm8S-f2z_vczHBdSrgiJibesdOP3ugYlxJvDDT3WSf3WW7cjAn8M3vZmCNTPWe6JEewsc6cDBiFWn9UUomulFUV_uucTsV_NXMd8nQ_Hs"",""e"":""AQAB""}]}"
SET ST=##class(%OAuth2.JWT).ObjectToJWT(.JOSE,.body,localpriv,localpub,.JWT)
d $system.OBJ.DisplayError(ST)
ERROR #8896: No private key found for alg: RS256.