21

JWTs typically include an audience claim. I've read in many places (articles, code examples, the spec itself) that you must check that the token is intended for you and not another audience.

I'm happy enough to accept that. I'm not planning on building anything that sends to JWTs to the wrong audience. But I'm curious as to why it's important to reject it.

You should be able to verify that the token was issued by an authentication server that you trust. So you have to accept that the claims in there are not fabricated.

The only risk I can think off is if the auth server produced different values, for the same claim, to different audiences. Other than poor namespacing, I can't think of a reason this would happen.

E.g.

{
  "aud": "foo",
  "roles": ["admin"]
}

Instead of:

{
  "aud": "foo",
  "foo.roles": ["admin"]
}

Perhaps the question could be better phrased as:

What bad things can happen if I accept another audience's (valid) JWT token?

2
  • Thinking aloud from scanning the link (I've not used JWTs): a company's finance system might have different "principals" for Order Entry and Payroll. Someone might be given a token with an audience of "OrderEntry" that shouldn't allow them to do anything in the Payroll part of the software.
    – TripeHound
    May 1, 2019 at 10:49
  • @TripeHound - from my understanding the JWT (OIDC ones anyway) isn't intended to provide authorisation, only authentication. So the JWT tells you who the user is (in the form of various claims) and it's up to the apps to determine what they want to let them do. E.g. Maybe they have a particular role, or perhaps they're from a particular group or country.
    – Andy N
    May 1, 2019 at 11:00

3 Answers 3

9

I would argue that in a sense you are correct in that there's nothing special about the audience claim that you couldn't handle yourself through namespaced claims and custom security checks.

The JWT specifications notes that the aud claim (as well as the other registered claims) are optional and that the application needs should define when to use or not use them.

As to why it's commonly advised to authenticate on audience, it's basically a simple and standardized way to test whether the incoming JWT is meant for your application. It can be a hassle to create namespaced tokens for each and every application you want the identity to work for. Following the standard approach also makes things easier if you need to integrate with 3rd party apps or identity services.

The only real danger I can think of is if you or the next developer forget to do any additional checks that are now necessary due to not using audience checking.

3
  • Marked as correct. But just a quick question - what sort of additional checks are you referring to? The 3 normal ones would be: [Valid signature, non-expired, audience]. If we drop the 3rd but keep the first 2 wouldn't that still be enough to know the claims were true?
    – Andy N
    May 2, 2019 at 11:08
  • @AndyN I was just thinking that with your scheme you would want to check the claim list to make sure you don't get misshaped JWTs since you don't have the standard names with the namespace. You can also of course authenticate against the other standard claims such as issuer. As you say though a valid signature and expiry check would be the practical bare minimum.
    – AlphaD
    May 2, 2019 at 11:26
  • Microsoft implores you to validate AUD and reject tokens that dont match your app, but they fail to provide a reason.. The problem with OAUTH protocol is that there are too many OAUTH Nazis that tell you what you must and must not do, without explaination. You make a simple case why there is no compulsion to rely on AUD May 16, 2022 at 23:13
15

Suppose I regularly use JWTs from AUTH SERVER to sign in to several several websites, including A and B. Without the aud claim, the JWTs would be identical. This would allow a malicious admin from A to use my JWT to authenticate to B.

7
  • Just to double-check: are you just concurring with my namespacing point (i.e. A and B were allowed to name their claims identically) or is this a separate issue?
    – Andy N
    May 1, 2019 at 13:39
  • In OIDC, "roles" is not a required claim. Authentication is perfectly valid without it. Hence, it is not safe to rely on role namespaces to prevent the type of attack I mentioned.
    – Irfan434
    May 1, 2019 at 14:02
  • No, of course not. All I'm saying is that systems sometimes use claims (role or otherwise) to determine level of access. Just because a user turns up with a JWT doesn't mean they get access. Or, to your point. How would B mistake an admin for A for one of it's own?
    – Andy N
    May 1, 2019 at 14:43
  • 1
    When the end-user uses the same token for both A and B, A knows what the token is, and could pretend to be the end-user to B.
    – Irfan434
    May 1, 2019 at 16:19
  • 2
    Your apps should not rely on audience to control access. Each app should have a unique security context where the roles of users are validated uniqely May 16, 2022 at 23:10
1

This is the same answer as Irfan434 gave, but I would like to explain it with an example to help explain how this can go really wrong.

Imagine you have a big JWT issuer, like Google.

Now imagine you have a low-security app that uses this JWT issuer for user accounts. Lets say it's a mobile app called "Earl's Eats". It's just an app to review restaurants, so maybe security isn't a top priority, or maybe Earl is evil and decides he wants to exploit his user base. Earl has thousands of JWTs. All of them are valid. All those users did really sign in to Earl's app.

Your app might be a higher security/risk/impact app however. Maybe it's a banking app. In the normal course of things: a user signs in, Google issues a JWT, you validate the JWT, you know who the user is, and you let them transfer money. If however Evil Earl starts sending you requests with JWTs he has accumulated from his users, you won't notice unless you are checking aud.

If you are using a big public issuer like Google, this is a huge problem. If you are using an internal JWT issuer, the issue is less severe, but it still opens you up to credential passing attacks.

TLDR

If you validate aud, a JWT says "This is Allice"

If you don't validate aud, a JWT says "This is Allice, or some one Allice trusts, or someone that person trusts, or someone they trust..."

1
  • Not bad except the TLDR (+1). "Allice + aud" = subject your app calls Allice. "Allice without aud" = subject some app calls Allice. So it's about context. On most auth servers, there's nothing to stop you copying another app's namespace, but you can't copy their aud. Or for a less malicious example, to stop your test app tokens working in production! (since their claims will all have the same namespace)
    – Andy N
    Jun 5 at 9:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .