Expected a payload property named aud with a(n) string value - keycloak

I am getting the following error message when trying to authenticate using JWT.
Now, on its face, this error is that I need to set the aud parameter in my JWT to a string - ok, I get that.
However, my IAM, Keycloak, is providing the following:
"aud": [
"broker",
"account"
],
Should I be manually changing this to only one of these values? I'm not quite sure what audience does and if I'd be losing information if I just decide to get rid of one of the values.
From my reading:
The audience aud claim in a JWT is meant to refer to the Resource Servers that should accept the token.
I don't think I need either broker or account - how would I change them to something else - a string value?
EDIT:
I just want to set "aud" to a single string value in keycloak. That's it.
EDIT2:
Both the Audience and Audience Resolve protocol mappers add the audiences just to the access token by default. The ID Token typically contains only single audience, which is the client ID of the client for which the token was issued. This is a requirement of the OpenID Connect specification. On the other hand, the access token does not necessarily have the client ID of the client, which was the token issued for, unless any of the audience mappers added it.

The fix for this was that both audience mapping as well as audience resolve contribute roles

Related

How to get the Username with OpenID Connect on ADFS Server

I just realized that the userinfoendpoint doesn't give any useful info about the logged in user.
Now, I saw that you can get an id_token from ADFS tokenendpoint. This id_token is actually a JWT which contains the unique_name.
Now my question is, if it is safe to use this info without signature validation (since we don't have the private key of the HS256 algorithm and validation is as far as I understood, a thing for the issuer not for the client).
• There are two scenarios to your question of whether it is safe to use this info from an ID_token. First, your client, i.e., the application or authorization server will validate the token just like it validates the access token for any tampering. Also, it can validate the issuer to ensure that the correct issuer has sent back the token. Since there are many libraries to validate an ID token, you should use them for ID token validation purposes.
• Also, only confidential client applications should validate an ID token as their token holds a secret while public applications don’t benefit from validating an ID token as there is always a risk of a malicious user who can intercept and edit the keys used for validation of the token.
• As you are speaking of the case when you don’t have the private key to the algorithm used for encrypting the ID token, it must be a confidential client application. Thus, validating the ID token on the lines of access token and confirming the below claims are validated by your token validation library, you can then use the information retrieved from these claims for your purpose. The claims that need to be validated are as follows: -
Timestamps: the iat, nbf, and exp timestamps should all fall before or after the current time, as appropriate.
Audience: the aud claim should match the app ID for your application.
Nonce: the nonce claim in the payload must match the nonce parameter passed into the /authorize endpoint during the initial request.
Please find the below documentation link for more in-depth details on validating the tokens and the inherent process involved in it: -
https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens#validating-tokens
No, sadly the userinfo endpoint only gives you a "sub".
You can validate the JWT yourself.
You should always check the signature.

Can I have the same audience claim value when using Sign In with Apple via an app and website?

I've implemented Sign In with Apple in my iOS app, and now I have also implemented it in my website. What surprises me is that both flows end up with a difference audience value in the id token, is that to be expected? The iOS app uses the app's bundle id, and the web flow uses the service id's identifier.
So for example in the iOS flow the audience is com.domain.app and in the web flow the audience is com.domain.siwa. When I'm sending the id token to my server where I am doing the validation logic, I now have to know where the id token comes from so I can use the correct audience. It would be easier if the audience could just be the same for both flows. Is that possible? Or should I just forgot about this and work with two difference audience values?
The reason why the audience aud claims of your JWT tokens differ is that, as Apple themselves puts clearly, the audience registered claim identifies the recipient for which the identity token is intended.
Simply put, as the audiences are literally different, the aud claim should & will always be different.
This is not unique to Apple and is actually taken from RFC7519: JSON Web Token, so trying to make the aud claim values the same is actually going to be against the JWT spec.
Here is how RFC7519 describes it:
The "aud" (audience) claim identifies the recipients that the JWT is
intended for. Each principal intended to process the JWT MUST
identify itself with a value in the audience claim. If the principal
processing the claim does not identify itself with a value in the
"aud" claim when this claim is present, then the JWT MUST be
rejected. In the general case, the "aud" value is an array of case-
sensitive strings, each containing a StringOrURI value. In the
special case when the JWT has one audience, the "aud" value MAY be a
single case-sensitive string containing a StringOrURI value. The
interpretation of audience values is generally application specific.
Use of this claim is OPTIONAL.
If you need to, I would say to just deal with different audience values but what are you using the aud claim value for anyway?
If you're trying to restrict specific features, for example, based on a certain "audience", feel free to use it however the use of this claim for business logic isn't really that widespread.
Other claims will most likely be better suited depending on what you're exactly trying to achieve here.
ID TOKENS
The audience for an ID token represents the client application, so you will have 2 different audience values. ID tokens are typically validated by the client app, eg in the mobile code, but using an API to do the work is also possible.
ACCESS TOKENS
Here is the OAuth standard behaviour:
Don't send ID tokens as credentials in API requests - send access tokens instead. Access tokens have an audience that specifies an API or a set of related APIs, eg api.mycompany.com.
Issue your own access tokens, where you can control the scopes and claims that your APIs will need for authorization - Apple tokens are not designed to be used in your own APIs
AUTHORIZATION SERVER (AS)
The optimal way to issue your own tokens is to let an AS manage the connection to Apple for you - as in this tutorial.
SUMMARY
Hopefully this gets across key points in case useful. Aim to base solutions on the standard design patterns that have been vetted by experts for many years. Sometimes vendor specific guides don't explain these principles well.

How to restrict a user to THEIR resources using JWT when there is no identity in the Access Token?

We have a REST resource like this:
/customer/{customerId}/bill
We want to use the JWT tokens returned from AWS Cognito to secure access to this resource.
The {customerId} here is not the Cognito user id, it's a domain specific id. We have added this domain specific id to the Cognito user as a custom attribute. It comes in the ID token that Cognito returns like this:
{
"sub": "xxxxxxxx-852f-474d-aa9e-a50fd832bcb8",
"aud": "xxxxxxxxsijed6uf54dh0uhi",
"custom:customerId": "4044",
"event_id": "xxxxxx-fc0c-4ffc-affa-f8987714fb2b",
"token_use": "id",
....
}
If we use this ID Token in Authorization: Bearer <ID Token> we can write code (custom authoriser or in-app code) that ensures the customerId in /customer/{customerId}/bill is equal to the value of custom:customerId in the supplied token, and we have secured our API.
But then we read that you should not use ID tokens to secure APIs . The key point being:
"The audience (the aud claim) of the (ID) token is set to the application's identifier, which means that only this specific application should consume this token."
So it seems we need to send an Access Token to secure the API. With Cognito, there is no way we can add any concept of who the user is into the Access Token. We can't add a custom scope like user:4044 for example.
What folks suggest as an approach here is to call the /userinfo endpoint of Cognito on the server-side with the supplied Access Token to learn who the user is. This would enable us to write code (custom authoriser or in-app code) that calls this endpoint and asserts permission. But it's an endpoint call for every request, which seems crazy.
One thought that crossed our minds was to use the Access Token to secure access to the API itself, but also require the ID token, either as a query parameter or a header to allow us do the fine grained access control. But that too starts to feel wrong.
Surely this is a solved problem? What is the right thing to do here?
Sorry, this question is a year old, so my answer is probably irrelevant. But for future wanderer, I would say that, given the limitations of cognito in allowing custom claims in the access token, a call to the /userinfo route is definitely the best way.
The API GATEWAY lets you cache authorizer response for a given user, so you won't be calling the endpoint on every request. Note that some implementations recommend it as a way to make sure that the token haven't been revoked.

What is the purpose of the --oidc-client-id parameter when setting Kubernetes up to use OpenID Connect?

The Kubernetes documentation related to OpenID Connect mentions that as part of setting things up you need to supply some parameters to the API server:
--oidc-client-id: A client id that all tokens must be issued for.
There is no other explanation about how this would map to, say, something returned by the OpenID Connect-conformant Google identity provider.
I don't know what this parameter value will be used for. Will it match against something in the decoded JWT token?
It looks like the id_token returned by the Google identity provider might contain something, once decoded, in its aud field (aud is apparently short for "audience"). Is this what the --oidc-client-id should match? Am I way off?
This can be explained from the kubernetes documentation on id tokens.
As you can see, identity provider is a separate system. For example this can be MS Azure AD or Google as you have shown.
When you register for a identity provider, you get important things in return. client id is one such important parameter. if you are aware of the openid connect flow, you need to provide this client id when you follow the flow. If the flow is complete, you will return an id token. An id token has one must have claim, aud which is the audience that token was issued for.
When you validate an id token you MUST verify you are in the audience list. More can be found from the spec.
Quoting from specification,
The Client MUST validate that the aud (audience) Claim contains its client_id value registered at the Issuer identified by the iss (issuer) Claim as an audience
Now, kubernetes uses bearer tokens. Here the tokens used are id tokens. To validate the token it should know specifically the audience. This enables the API server to validate the token is issued for the particular client who made the call. Thus authorising the call to to success.

OpenID Connect Standard: Authorized Party azp Contradiction

In the OpenID Connect spec the azp (authorized party) claim seems to have a contradiction.
In the ID token definition section 2 it says:
azp
OPTIONAL. Authorized party - the party to which the ID Token was issued. If present, it MUST contain the OAuth 2.0 Client ID of this party. This Claim is only needed when the ID Token has a single audience value and that audience is different than the authorized party. It MAY be included even when the authorized party is the same as the sole audience...
But in token validation section 3.1.3.7, one of the steps seems to say the opposite:
If the ID Token contains multiple audiences, the Client SHOULD verify that an azp Claim is present.
Could anyone shed some light on this apparent discrepancy? Only the second instance uses declaratory language, so I'm leaning towards favoring that in my implementation.
You're correct, the whole azp situation in OIDC is confusing. For what's it's worth, they have an open issue associated with it; see OIDC - Issue 973 (azp claim underspecified and overreaching).
From the definition of "aud" in JWT and its use in Connect's ID Token (relevant spec text is copied below), it seems that that the client id of the client/RP that made the authentication request has to be one of the values, or the only value, of the "aud" claim in the ID Token. That's logical and consistent and provides reliable and interoperable guidance to implementers about producing and consuming the ID Token. I think that the client id of the RP/client that made the authentication request should always be represented in the aud of the returned ID Token.
The text around "azp" in the ID Token section and the ID Token Validation section seems to maybe suggest something different, however. Like perhaps that the client id of the RP/client that made the authentication request could, in some totally unspecified circumstance, be the value of the azp claim and that the aud would not identify that client as an intended recipient. Am I misinterpreting things?
Personally, from the client application developer perspective, the best course of action seems to be honoring the ID Token validation rules which always imply that the value within azp will also be present as an aud. However, according to what's available online Google seemed to use it a bit differently so you could have a value in azp not listed within aud, so there may be situations where you play by Google rules and not (just) OIDC.
If you're implementing an OP a probably good option is also to entirely stay away from including azp in your issued tokens if possible or only include it when using multiple audiences with one of them being the value also in the azp.
I think the two sections are not conflicting each other on the concept level (a bit confusing on the wording though).
if there is a single audience which is different from azp, it makes senses to have both azp and audience to show that difference. In a multiple-audience case, at least one of the audiences will be different from azp and hence azp must be present to make it clear.
azp usually equals to client id (the application requests the token). audience of the token can be the app itself or another application which receives the token for validation.