Malformed JWT for Token Exchange

I am working through doing a Token Exchange as laid out in the CIS2 Separate Authentication and Authorization, using the Sandbox Environment, and I keep getting back a “Malformed JWT in client_assertion” error.

The JWT is valid when checked with JWT.io.

The most recent example:
eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6Ik1ULVNhbmRib3gtMSJ9.eyJpYXQiOjE2ODk4NjE5ODAsInN1YiI6Im1NQ3NVR3VteE8wbU05ekM4S1NNczJLSUh3dFJNUkRRIiwiZXhwIjoxNjg5ODYyMjgwLCJhdWQiOiJodHRwczovL3NhbmRib3guYXBpLnNlcnZpY2UubmhzLnVrL29hdXRoMi90b2tlbiIsImlzcyI6Im1NQ3NVR3VteE8wbU05ekM4S1NNczJLSUh3dFJNUkRRIiwianRpIjoiNDhlMzNiMDMtZDljYy00ODM2LTgwNzEtODQ3YTFlNDMzNmYyIn0.U7pnXT5opYgFF_rDhu0G7sj-ZtxA8iWV-Sa6s1Sg_J-Y0KN1ZWHnTMBf9xsAc9thGkhqp3V–Dkke7qCC4Q2piEAnGW7JKagtrzh5O05Pc3iOivcTUauQwHYZB8W78TuKKDxPtPbXs4pyYhTjP-Vuy4ghKW4HUe-xLdegZ1crOVF3-kyB2XS0g-_HJqXffoFKKqQwpacB70z6Z0h6zI3yjPM-zQm9IyrwGUobib9g1E63EbaQ8b6gRdaMfr71Dj2fG5veD65QASpXIUvW1RYH6Dj-E6vrq9-uDUu3KHEpDhUvRLNQMxn8ThPkl208CALabV2dQ6IXPQOX_JBwcD6bpVZWQXaR6lB1VthC0XDmWyFDz2q0uD2X9SItARWt1hWRrUEzKsogWHyOd4ALnBIhtH1qo4Y9pvnY0SPlZoZfkLNepVC9l1-Ilk7cOJoovB-BgLc6mpnSlVyilc3d-wDEZLIeHW2Y0tbRJRrLKKIVY1EVQLX7mnz7iynxZKIw_TeUTEuNBV6QHX3gJj21VACGZi2UV9AdQEyXNnC7sxFoTR_lkJUXZUVQTyTbBCtm2mQU7E-j1iymDqKsyv6zb8r76CzO2umxwmu-J1u74CekOqrXMBBd1hYSbfRnhSfCaFxWsVGexWP-faLlWk5KnL0pddVzIF4KIBWpW14kmzVSJQ

Any help would be appreciated, Thank you.

Hello glabonte,
Did you use the Token in postman or via code?

I’ve tried both, but have resorted to Postman for the short term.

Hello glabonte,
The Team have taken a look and the JWT looks fine, but it is possibly how its being created is why its invalid.
Can you list the App ID so we can check the App looks as it should be, thank you.

Hi @alan.rawlings2,
The app ID is 33f00de9-75c6-44fb-84f8-31069537068b.

hi @glabonte
i am working on a similar thing and wonder where the Relying Party code(client_id) should come from. :pray:

Regarding the question, the sandbox env requires token in order to consume API ?

Hello glabonte, Which specific API does this relate to?
1

Running your token through JWTIO gives the following error;

“Looks like your JWT signature is not encoded correctly using base64url (RFC 4648 - The Base16, Base32, and Base64 Data Encodings). Note that padding (”=“) must be omitted as per RFC 7515 - JSON Web Signature (JWS)

Maybe this will help?

I am trying to get started with eRS in Healthcare worker mode.

Hello glabonte,

The team have adivsed, if you are in the sandbox environment the URL is sandbox.api.service.nhs.uk/oauth2, not int.

I have corrected the url I am targeting to be the one for the sandbox environment, but I am still getting the same “Malformed JWT in client_assertion” error.

The most recent JWT token I’ve generated is:

eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6Ik1ULVNhbmRib3gtMSJ9.eyJpc3MiOiJtTUNzVUd1bXhPMG1NOXpDOEtTTXMyS0lId3RSTVJEUSIsInN1YiI6Im1NQ3NVR3VteE8wbU05ekM4S1NNczJLSUh3dFJNUkRRIiwiYXVkIjoiaHR0cHM6Ly9zYW5kYm94LmFwaS5zZXJ2aWNlLm5ocy51ay9vYXV0aDIvdG9rZW4iLCJqdGkiOiI2ZWRiMTc0OC1iZmIzLTRhNDAtYmVlMi1lM2VlYjFjNzk5NDgiLCJleHAiOjE2OTcyMTE5OTJ9.kAoFeMJsUiOht8i7VrTWLB8Uu9tCM0Ras57ySrjAS4MIOdAZZAyvnt9LGJoL3mqUOAQTkqS8_AwBZ–EJSlOskBsjDKTWm5aFRMzOehd66tlepfrfbU3HU8KVUlQLorYojgD0qLemYGQ83_LPtEVNKgZH5lKkm3qepDe9kq4F5D1CpMqnYqWDTm5pW8BJ4XHa85wJwm9YDonJ_M2qwG_SSd9_QjwxGm-wcfK_It-yy3uIu54B3K1fDSux2oHmvzNjSFPAHxbQKTNA34JMvNhSNQqGk9WUkDEfRBbd_yJjZkCurAIGwX_i_uZXzykD9w-gbrx0St_5hDX62xNJF4WOBz0-1_LxsZKOsrb2XU5OwYX94P65UACNQbezLmOf4X21fI6ACOUTYpIVND7JbgUjwhjrTbqZ7I4LKF4HdScC_5JommJ9Y6BVexR8Zo_P7RWVncXZUII6E6WF76pIllVDnDPFdvb7qHEc4spsTq04mBJyCZqd10PYBb8bKeYN4N4l7jicoSVl_PPwtghFbyzZnxSoP9QR0t5dBaY2TWebMh3MhuSmGnpwxP_9I1_Gj_NlL-xFhypFsBuBGzHenzmdVWeCJlsOiGwXf0Z8O-0Yq_PnffMuxceY9IsKbJ18ejz9L7vqlu1b79Hnhq8VWisnmac4IVhTgsBUDpXdKbSzcE

@alan.rawlings2 Any Suggestions?

Hello glabonte,
Is this still causing issues?
I have in either event passed this into our Support team for further guidance.

This is still causing issues.

Hello glabonte,

The support team have provided the following update.

The JWT does decode though:

Header

{
“alg”: “RS512”,
“typ”: “JWT”,
“kid”: “MT-Sandbox-1”
}

Payload

{
“iss”: “mMCsUGumxO0mM9zC8KSMs2KIHwtRMRDQ”,
“sub”: “mMCsUGumxO0mM9zC8KSMs2KIHwtRMRDQ”,
“aud”: “https://sandbox.api.service.nhs.uk/oauth2/token”,
“jti”: “6edb1748-bfb3-4a40-bee2-e3eeb1c79948”,
“exp”: 1697211992
}

Header

  • alg and typ: correct
  • kid: present in the JWKS stored against the app

Payload

  • iss and sub are correct values for the App
  • Has all necessary claims

Something is wrong with the JWT preventing it from being decoded. The error message in JWT.io may point to the issue.

To further aid our diagnostics can you provide:

  • The full request coming out of postman (I think you can ‘copy request as cURL’ or something similar)
  • Details of how they are creating and signing the JWT

CURL request:
curl --location “https://sandbox.api.service.nhs.uk/oauth2/token” --header “Content-Type: application/x-www-form-urlencoded” --data-urlencode “client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer” --data-urlencode “grant_type=urn:ietf:params:oauth:grant-type:token-exchange” --data-urlencode “subject_token_type=urn:ietf:params:oauth:token-type:id_token” --data-urlencode “subject_token=g9NGlC3qzmAFi5VFe2TCVLAkFGAK” --data-urlencode “client_assertion=eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6Ik1ULVNhbmRib3gtMSJ9.eyJpc3MiOiJtTUNzVUd1bXhPMG1NOXpDOEtTTXMyS0lId3RSTVJEUSIsInN1YiI6Im1NQ3NVR3VteE8wbU05ekM4S1NNczJLSUh3dFJNUkRRIiwiYXVkIjoiaHR0cHM6Ly9zYW5kYm94LmFwaS5zZXJ2aWNlLm5ocy51ay9vYXV0aDIvdG9rZW4iLCJqdGkiOiI3MmVlNTg1My00YjdmLTQ1NTQtYjI3NC04YjA3YmUzMGIxMTQiLCJleHAiOjE2OTg2ODU1Mzl9.QK4gG1Y25EJKQWgKqLvvFTjactSYWCVQwY3xVDcvfIEZjZf5qoUl_4KJUOc5pS7fsTwlDLPdBU1F4zIgaCj6-v5g_yAY7xiwKiIoq3tDhty8pHD2TyXGoQmCf-UijI0l1hN2zYmZ_86FrZcdxW-CRD0–Nh-RxFXnOZAKwEUGdDCgMKVZawe7LIcpSTcyCIWr3n7jHoc3SgpUc6twV_wvagigajybLs4Lc2cGVUg9npQHd8QU73iYYzmVIiO1nWIpojBtTJeJC446CP3K9ye7BhCg4GNechrABLGWPUBcdbY4nthdNAGs8Se2kp1rZS7_4RWEnr-f7NPQ2F6vtzzsyOCytV081d5HnmkMuuttOfxr3-pVmHEiPbMCI457SaPlzlbxpvvBv9mv0CXKz6MERJB3jlAsIWzmxeXYaXE2rkgiCU8wOebqbIIPjwPDkINqi0F4_mvzigdUW5bZy8bBXRi_qhn-UUGSzbAxXx_YyPOOgnapYI_TU6Hjl-9emAwtc96yp7vS499vYeZGzHOLT2pvWyhm4JpXGEG7GS5pIBHnc8ofo887GyGmtM62xXFoJr0yfNDGbqiVLc6FseVVSpxz7b2ksRJOlfb3FmlC0y8JKdlXM8-W3-Bqk_bza3QtJj7yMfUyZ1hYzh9PtzfIHFYsvG6UX63k_Z9sFdkcvQ”

I’ve been building the header and payload in application code. I’ve checked with our systems developers, and they told me are using the Microsoft CryptoAPI to generate the JWT from the header and payload.

Thank you glabonte,

I have our support team looking into this.

Hello glabonte,

Looks like the signature contains an en-dash: CRD0–Nh

Valid characters are letters A-Z , a-z , and numbers 0-9 , and minus - and underscore _ (its possible an editor has converted a double-hyphen to a en-dash?).

I believe thats an odd artifact of how things are being posted. Two sequential minus signs - get converted into the en-dash when viewing the post.

I’ve generated a new CURL request that is still Erroring out claiming Malformed JWT.

curl --location "https://sandbox.api.service.nhs.uk/oauth2/token" --header "Content-Type: application/x-www-form-urlencoded" --data-urlencode "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" --data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" --data-urlencode "subject_token_type=urn:ietf:params:oauth:token-type:id_token" --data-urlencode "subject_token=WrC0jcal1PAXzlOntaRIm0icGOKo" --data-urlencode "client_assertion=eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6Ik1ULVNhbmRib3gtMSJ9.eyJpc3MiOiJtTUNzVUd1bXhPMG1NOXpDOEtTTXMyS0lId3RSTVJEUSIsInN1YiI6Im1NQ3NVR3VteE8wbU05ekM4S1NNczJLSUh3dFJNUkRRIiwiYXVkIjoiaHR0cHM6Ly9zYW5kYm94LmFwaS5zZXJ2aWNlLm5ocy51ay9vYXV0aDIvdG9rZW4iLCJqdGkiOiIxYThhMjQyNi0zOWQzLTRiOGUtYmE4OC03M2RiNGNkM2ZkNWUiLCJleHAiOjE3MDEzNTIyNTV9.fXv5KLx9u9RMLCVwm3NJ7YPBMXWTdgn5xu3A2dbvbzVRov0QZ34A7IlxmELB3J0iEARrPNtLvP1NKnC8CWlXZmd9wmwCGtPGRW76JiXwnwq3fqQH_LqiTT4c13JkMS7xaTw7hjQmup95LSiGnngvi0j88RDKQa8EREdDCdyoR8NsagiXxyNTWC44k-YBJPjJQlULiWaU33OHFYY6RSkU-XxNpItTIIXC2p8jXaJmsUnCBv6r1Bx-qNOyTotqq5k1BllKQhJiXn1GxVHIPz2_tKPDucd1f78xlLDOEp74dsTclieyL5Zfc8-zblI5zhT3HFI83EHg-h-CigAfq356yiQ_WFrQrAlTZAKVQ0X7dhq36qSlVOMj1dLK83gcQGqdXRFzox9X4OVHypz87MUIm-soamjgmlkj4zg28NRJ9Gm4Joo3xlAwEJ4Dn95T6IW1ao-yamycmprUup5AR4HtapvTjMiaswun3zjyNiDkJoP7-NpXxsMLZ6u_PMSrhtmi-ttAuRCXTM9BgcQKbXLT7P3CcJLvuYFAuF72QmGr1kE50AZqCeltYUWQmEe0ESY9KF4zp_gKuR0_QXtEOzZidyY9AMb-WYYzHLIi7k6jYuOZT5puzP_bapRvjeM0OZaiKuSi5d74iadQeoe3pkglKgA1k_4HQHJFUfEXoq_hnZ4"