FHIR Chat · backend services oauth client audience input in the token... · smart

Stream: smart

Topic: backend services oauth client audience input in the token...


view this post on Zulip Sagar Shah (Sep 07 2021 at 16:21):

Hello everyone,
I suppose SMART does not dictate anything about audience claim when calling token endpoint (with backend services client). As I see in documentation, it refers passing only these 4 parameters.

  • client_assertion (This is the token created & signed with audience as token endpoint of authz server. But my question here is about the audience = specific fhir base url as an additional parameter to be passed when calling the /token endpoint itself)
  • grant_type
  • client_assertion_type
  • scope

Does it not require to pass audience claim with FHIR base url as well in this workflow in addition to above 4 parameters? Is it only intended for authorization_code workflow? Appreciater your views.

view this post on Zulip Michele Mottini (Sep 07 2021 at 16:39):

yes, no other parameters. The audience is inside the JWT

view this post on Zulip Sagar Shah (Sep 07 2021 at 17:54):

Thank you @Michele Mottini for clarifying!

view this post on Zulip Josh Mandel (Sep 08 2021 at 17:16):

I suppose SMART does not dictate anything about audience claim when calling token endpoint

aud is a required claim; we state "The FHIR authorization server's "token URL" (the same URL to which this authentication JWT will be posted -- see below)" at https://hl7.org/fhir/uv/bulkdata/authorization/index.html#protocol-details

view this post on Zulip Josh Mandel (Sep 08 2021 at 17:16):

(As Michele says, this claim is inside the JWT.)

view this post on Zulip Josh Mandel (Sep 08 2021 at 17:17):

This authentication JWS claim is distinct from the aud parameter to the authorize endpoint of a SMART App Launch.

view this post on Zulip Sagar Shah (Sep 09 2021 at 20:49):

Ok. My question was mainly at the request part for client credential grant type using token endpoint on Authz server. The token returned by Authz server does not includ 'aud' claim unless it has been asked by the client in /token endpoint's audience parameter in addition to the scope, client_assertion_type, grant_type and client_assertion parameters. and SMART does not dictate anything for that audience parameter to be passed as fhir base url in the /token endpoint

view this post on Zulip Josh Mandel (Sep 09 2021 at 21:26):

The token returned by Authz server does not includ 'aud' claim

The access token (access_token) returned by the authorization server is entirely opaque; it doesn't not include any claims that the client can inspect.

The identity token (id_token) returned by the authorization server (if/when clients are granted scopes like openid fhirUser) contains its own "aud" claim indicating the audience for whom the identity token is intended -- specifically, this claim is what tells the client "this ID token was meant for your app"; it makes ID tokens safe for the app to pass around among different components, preventing someone from "injecting" an ID token intended for a different client into a workflow

view this post on Zulip Sagar Shah (Sep 09 2021 at 21:29):

Agree on id token part. but dont we need to have aud in the access token itself, if the access token is a JWT token? Is that not needed?

view this post on Zulip Sagar Shah (Sep 09 2021 at 21:30):

My challenge is our Authz server does not return aud in the signed JWT token unless asked by the client and SMART does not mandate passing audience paramter in the token request for client credentials workflow. Is the question/challenge more clear now?

view this post on Zulip Josh Mandel (Sep 09 2021 at 21:46):

but dont we need to have aud in the access token itself, if the access token is a JWT token? Is that not needed?

If the access token is a JWT, then you've got some rules governing the token format -- that's outside the scope of SMART (but to your point: yes generally those rules would probably dictate claims...)

view this post on Zulip Josh Mandel (Sep 09 2021 at 21:48):

Is the question/challenge more clear now?

Not yet... I'm not sure what you're trying to do.

does not mandate passing audience paramter in the token request for client credentials workflow

What would it mean to "pass an audience parameter in the token request"? Audiences claims are generally associated with a digitally signed artifact, so you can answer the question "for whom was this artifact created/intended/signed".

view this post on Zulip Sagar Shah (Sep 09 2021 at 22:51):

Ok, trying one more time. Here's extract from SMART launch page.
"The resource server also validates that the aud parameter associated with the authorization (see above) matches the resource server’s own FHIR endpoint"

I assume resource server will find aud parameter from the token from the authz server. And try to match with its own FHIR base url.

Question: Is this check not required to be fulfilled when the backend services client call the FHIR resource APIs.

If this check is required to be implemented on the resouce server for backend services flow as well, then how can we guarantee the aud parameter is passed in the request?
As I see, aud is mandatory only for app launch with authorization code flow but not for client credentials flow. So backend services client using the client credentials flow may not pass the aud as fhirbase url, when authenticating with authz server and so in return it will get token but that jwt token may not have aud claim in it. Now using this token, when FHIR API is called by the client, FHIR resource server will reject the request as aud claim is empty.

So in this flow, who's at fault?

  • Client, who did not request for audience in this flow?
  • Authz server which did not return aud claim in the JWT token OR
  • the resource server that rejected the request on ground that token did not have an aud claim.

view this post on Zulip Josh Mandel (Sep 09 2021 at 23:00):

Thanks, I now understand that you're looking at implementing a protected endpoint where it is not the client app but the authorization server responsible for looking inside of the access token.

The language in your excerpt is documenting the fact that when a smart app first launches, it tells the authorization server which fhir server it is planning to talk to -- that's the aud parameter that is passed into the authorized endpoint at app launch time. Eventually when you issue an access token, your authorization server needs to associate that with the audience named in that first step -- we don't specify exactly how you need to do this or what you need to consider to be a match, it's just a security issue for you to be aware of, to make sure that you are using tokens intended for the API endpoints where they are used.

If your authorization server only protects a single fhir server, this check might be unnecessary; but if you use a common authorization server with multiple different API servers, this is just a reminder that you need to make sure the access that was granted is valid at the API server where it is being used. We don't say how you need to accomplish these checks; they don't need to be based on any specific parameters inside of a structured access token. Those details are up to you.

view this post on Zulip Sagar Shah (Sep 09 2021 at 23:09):

Thanks @Josh Mandel for clarifications and apologies for the confusion and not making my question clear (dur to my wordings). I will probably check with Authz server implementation as well in order to determine how aud claim is being added in the access token and if that can be implemented even when client does not provide that in input for client credentials workflow. This particular behavior is causing our inferno tests to fail related to multi patient api as FHIR api is looking for aud claim(in access token), which is not present in the token issued by Authz server

view this post on Zulip Josh Mandel (Sep 09 2021 at 23:10):

Can you point me to the relevant test in the Inferno codebase? Just want to make sure we are talking about the same thing.

view this post on Zulip Sagar Shah (Sep 09 2021 at 23:22):

I am referring to the test here. We get tokens correctly but when we call FHIR API with that token, FHIR API fails to honor the request because FHIR API is validating for the aud claim in the JWT token, which is missing and the reason it is missing because app/client did not pass audience with fhir base url value in the parameters when calling /token endpoint on authz server image.png

view this post on Zulip Josh Mandel (Sep 09 2021 at 23:26):

from that screenshot I see a whole suite of tests about bulk data access. I have to admit I'm not entirely clear about what test is failing and why. Perhaps you can share a failing test example, including the inputs and outputs?

view this post on Zulip Sagar Shah (Sep 10 2021 at 00:55):

Took some time to run the test again. Here's the result
image.png

Here's the JWT access token being used for calling the FHIR API - https://fhir-qa-1.test.yourcareuniverse.net/tenant/7db7dfb5-2f73-4b96-bcf1-131410518850/Group/d0612fa3-88ae-4063-8eb8-06b33b31d61f/$export

Token:
eyJhbGciOiJSUzI1NiIsImtpZCI6InB1YmxpYzoxZDk1OWU2YS05YzM1LTQzZjktYjRmZC0xNjk4YWQwOTY1NWUifQ.eyJhdWQiOltdLCJjbGllbnRfaWQiOiIzMTM4NjM4Mi0yNDIzLTQxMTYtYTdiZC0xYWYxYzk0YzE0NGIiLCJleHAiOjE2MzEyMzY3OTksImV4dCI6e30sImlhdCI6MTYzMTIzNDk5OSwiaXNzIjoiaHR0cHM6Ly9pZHAtcWEtMS50ZXN0LnlvdXJjYXJldW5pdmVyc2UubmV0LyIsImp0aSI6ImJlYWUxYjczLTYxMjUtNGFjYS04YmVkLTMxMTExZTRlYjVlZSIsIm5iZiI6MTYzMTIzNDk5OSwic2NwIjpbInN5c3RlbS9NZWRpY2F0aW9uLnJlYWQiLCJzeXN0ZW0vQWxsZXJneUludG9sZXJhbmNlLnJlYWQiLCJzeXN0ZW0vQ2FyZVBsYW4ucmVhZCIsInN5c3RlbS9DYXJlVGVhbS5yZWFkIiwic3lzdGVtL0NvbmRpdGlvbi5yZWFkIiwic3lzdGVtL0RldmljZS5yZWFkIiwic3lzdGVtL0RpYWdub3N0aWNSZXBvcnQucmVhZCIsInN5c3RlbS9Eb2N1bWVudFJlZmVyZW5jZS5yZWFkIiwic3lzdGVtL0VuY291bnRlci5yZWFkIiwic3lzdGVtL0dvYWwucmVhZCIsInN5c3RlbS9JbW11bml6YXRpb24ucmVhZCIsInN5c3RlbS9Mb2NhdGlvbi5yZWFkIiwic3lzdGVtL01lZGljYXRpb25SZXF1ZXN0LnJlYWQiLCJzeXN0ZW0vT2JzZXJ2YXRpb24ucmVhZCIsInN5c3RlbS9Pcmdhbml6YXRpb24ucmVhZCIsInN5c3RlbS9QcmFjdGl0aW9uZXIucmVhZCIsInN5c3RlbS9Qcm9jZWR1cmUucmVhZCIsInN5c3RlbS9Qcm92ZW5hbmNlLnJlYWQiXSwic3ViIjoiMzEzODYzODItMjQyMy00MTE2LWE3YmQtMWFmMWM5NGMxNDRiIn0.VuyAX83kfodmdi1JWiDfIxAUYiCxdq5-BubKqFVIocTWsLqqnHZ4HaK0foDZBAoyyIRvjo8boLHcZO7avClocTX5T8sKoztRQFXR4O0ALihzuJG-g2_FZiFmE7gTPogk2DVQer6z4be-DfNFfhQDhgrCbJoBGRl9PyO98EuzXSohhYe_sxyPF4IgcN36aPjM3dhxEe707obmEu7ZsejwleLWM3aO-Kl6w64dtOM5u8iZPwaW6ZvJcuRvfd0MQN_eCMdnGhyqd8KEr_gCa16LtphGvY1T1qenuf6gtAbLfXwz1CL2YIGRvX2KKVOHuUPKHRA0T3SXJ2BjTtwPd-EhkG4KoZfYjZq0TIsYTtAM-mMo4QFbV17FNVokAM8ZsFz9uy0LG1s6YxphQwz1ydrfuW9itP28J5miafB0FDeyxni6RYPDFVBULJGLXp2SUOF9fIQAZFXJB38Bx_MkKQT7hN4BylPKecY7hpsdKRNNyahhphf1gXA3PoKXGyavO3yTIkgflnjhQpN5DqffApEJNOxSW9DMoRnmDlf4LnEk0RbX9USNZkLdiRgBj0HX1j1PFmNOMS2SJRKvyRRRgd4iazvGxeXfafnc77JfQzpaw6IEx6uDPv2Wya2ZyZcmi8MRU6MK-MiN9YvKDhhLSCuIrm0rgIpURgVLISFTL78oTKM

FHIR response is following but root cause underneath is no aud claim found in the token
{
"resourceType": "OperationOutcome",
"text": {
"status": "generated",
"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\"><h1>Operation Outcome</h1><table border=\"0\"><tr><td style=\"font-weight: bold;\">error</td><td>[]</td><td><pre>Invalid access token</pre></td></tr></table></div>"
},
"issue": [
{
"severity": "error",
"code": "security",
"diagnostics": "Invalid access token"
}
]
}

And Authz did not issue aud claim in the JWT token because client did not requested that being optional parameter in client_credentials workflow when calling token endpoint

view this post on Zulip Josh Mandel (Sep 10 2021 at 01:34):

From the report above, it looks like Inferno is acting as the API client, and your server is hosting the $export operation, yes? In this context, the "Invalid access token" error is coming from ... your server? In other words... is your server FHIR failing to validate the access token that your authorization server issued to (the client) Inferno? If that's what's happening, this seems like an internal detail on your end -- or if I'm misunderstanding, it'd help if you can share any pertinent logs/resuls.

view this post on Zulip Sagar Shah (Sep 10 2021 at 01:59):

Your understanding about roles played by inferno, fhir api hosting $export operation and auth server is correct. And the reason FHIR server is failing is... because, we implemented following check on our FHIR Server (Resource server).

As per SMART criteria: "The resource server also validates that the aud parameter associated with the authorization (see above) matches the resource server’s own FHIR endpoint"

And hence FHIR Server is recognizing the token as valid, but still not granting access to data/API because the token does not have 'aud' claim.

I am not certain, if in this flow (client credentials flow and not authorization code flow) FHIR API should be mandatorily looking for aud claim in the token (the way it does during authorization flow because aud parameter is mandatory during that time due to the above SMART on FHIR criteria)

view this post on Zulip Josh Mandel (Sep 10 2021 at 02:07):

Again, we don't stipulate anything about token formats. As a server, you're responsible for ensuring that you only provide access when the requester presents a valid access token (and one of the criteria for validity is that the access token must be intended for your server; that's not a subtle point, and it's all the "audience" requirements are about. These requirements are internal functional detail about your server's behavior, not something that's being tested in the Inferno scenario you're referring to).

view this post on Zulip Josh Mandel (Sep 10 2021 at 02:09):

In the client credentialed flow, there is no FHIR API "aud" URI passed into the authorization request, because there's no authorization request (just a token request). You only need to make sure that the access token being presented is valid for use at the endpoint where it's being used.

view this post on Zulip Sagar Shah (Sep 10 2021 at 02:49):

So you mean that SMART does not mandate that aud claim to be available in the jwt token for resource server to validate and match? It could be done in different ways. My understanding from previous SMART criteria was that SMART requires aud claim in JWT TOKEN that needs to be validated by FHIR API.
I guess you mean that validation of aud still needs to happen but "how" is left to the resourceserver and authserver. Is that correct?

view this post on Zulip Josh Mandel (Sep 10 2021 at 02:54):

Correct. We mandate nothing about access token format.

view this post on Zulip Josh Mandel (Sep 10 2021 at 02:55):

Resource servers just need to ensure somehow that the tokens they accept at an endpoints are intended for use at that endpoint.

view this post on Zulip Sagar Shah (Sep 10 2021 at 03:00):

Thanks @Josh Mandel for this detailed discussion and clarifications. It does help a lot! Appreciate all your time and effort throughout!

view this post on Zulip Josh Mandel (Sep 10 2021 at 03:02):

Absolutely -- happy to help!

view this post on Zulip Lloyd McKenzie (Sep 10 2021 at 14:29):

(@Josh Mandel - which thread was this intended for?)


Last updated: Apr 12 2022 at 19:14 UTC