Beta

Create a tenant

A new tenant starts with its own users, OAuth settings, audit history and logs. You are its first Tenant Admin.

BTL Admin

Issuer, audience, and authorized party

All domains, identifiers, and tokens in these examples are fictional.

Providers and relying parties said that everything the printer trusts about the photo service hangs from one value, its issuer. From delegated access to sign-in promised that the printer would refuse an ID token issued to the collage app. Both promises are kept by comparisons that look trivial, one string against another. What matters is what the printer compares against, and how a near match can slip through.

Matching the issuer

The printer compares iss with the issuer stored in the pending attempt, https://auth.photos.example, character for character. The comparison is case-sensitive and makes no adjustments, so each of these fails:

https://auth.photos.example/         trailing slash
https://Auth.Photos.Example          different case
http://auth.photos.example           not https
https://auth.photos.example/test     different path

Some of these would reach the same web server, and that is beside the point. An issuer identifier is a name compared as text, not an address to be tidied up before use. It is also the namespace for every sub the provider issues, so a printer that let near matches through would have to decide which of them are really the same provider, and an attacker would only need one it decided wrongly.

The path is part of the name. OpenID Connect allows several issuers on one host, told apart by path, and treats them as unrelated providers. As Providers and relying parties mentioned, services that host sign-in for many organizations often give each organization its own issuer this way:

https://id.workplace.example/org-7731     one company's issuer
https://id.workplace.example/org-9020     another company's issuer

A service like this often signs every organization's tokens with the same keys. A valid signature then shows that the service issued the token, not which organization it speaks for. Only iss says that. Now imagine a relying party that serves several business customers on this service and, to avoid configuring each one, accepts any issuer beginning with https://id.workplace.example/. It accepts tokens from every organization on the service, including one an attacker can create in a few minutes. In their own organization the attacker controls the directory and can create a user with any name and email address. If the relying party finds accounts by email address, or by sub without its issuer, that user signs in as somebody else.

The safe arrangement lists each accepted issuer exactly. An application that really does welcome any organization on such a service treats each issuer as a separate provider. It stores the issuer with every account link, and never lets a token from one organization sign in to an account linked through another. Supporting several providers returns to keeping providers apart.

Where the expected value comes from matters as much as the comparison. The printer took https://auth.photos.example from its own configuration when you selected Continue, and stored it with the attempt. It never takes the expected issuer from the token being checked, which would only compare the token with itself. At the callback, the printer compared the iss response parameter with the same stored value before it sent the code anywhere. The ID token's iss repeats that comparison on a value the provider signed. Provider discovery shows where the configured issuer and its key set come from.

Checking the audience

Moments after signing in to the printer, you also signed in to the collage app with your photo account. The photo service, which knows that app as the client photo-collage, relied on the session you had just started, asked you nothing, and issued the collage app an ID token about you. Decoded, the claims that matter here read:

{
  "iss": "https://auth.photos.example",
  "sub": "user-2048",
  "aud": "photo-collage",
  "exp": 1790845520,
  "iat": 1790845220
}

Everything about it is genuine. The photo service signed it with photos-rs-2026-09, its issuer is right, it names you, and it has almost five minutes left to run. If it reached the printer, its signature would verify there too. Only aud shows that it was issued to someone else.

In the printer's website sign-in, a token issued to another client has no easy way in. The printer validates only tokens from its own token requests, and the photo service redeems only codes that were issued to the printer. ID tokens travel other routes, though.

From delegated access to sign-in imagined the printer's phone app running the flow itself and passing what it received to the printer's backend. With OpenID Connect, the app passes its ID token, and the backend checks that the token is addressed to the phone app, a client the printing company registered itself. If the collage app's operator, or anyone who copied a token from the collage app, sent the backend this token instead, the audience check is what refuses it. Older flows that return ID tokens through the browser, covered in Understanding implicit and hybrid integrations, offer still more routes. The audience check is the one that works on all of them.

The claim comes in two forms. With one audience it is usually a plain string. In general it is an array:

"aud": "photo-printer"
"aud": ["photo-printer"]
"aud": ["photo-printer", "photo-collage"]

The printer accepts the first two, which say the same thing. The third contains photo-printer, but the specification requires the printer to reject it anyway, because it lists an audience the printer does not trust. Every party named in aud was meant to receive the same token, and any of them could present it to another. A token addressed to both could come from the collage app as easily as from the printer's own exchange, and nothing in it would show which. An extra audience is acceptable only when the printer has a reason to trust it, such as another registration of its own, and then the printer lists that value in its configuration rather than accepting whatever appears.

The client ID is compared exactly, like the issuer. Photo-Printer is a different client.

The authorized party

azp, the authorized party, names the client that an ID token was issued to. It was meant for tokens whose audience is not simply the client that asked for them: a single audience that differs from the requesting client, or several audiences, where aud alone cannot say which of them asked for the sign-in.

In practice it appears with arrangements that go beyond the core specification. Some providers offer a variation on the phone app design above: when one company registers several clients for one product, its phone app can ask for an ID token meant for its web backend. That token's aud names the backend's client ID, and its azp names the phone app, the client that requested it. The backend checks that it is the audience and that the authorized party is one of its own clients. What those values mean, and when they appear, is defined by the provider's documentation.

The current text of OpenID Connect notes that azp otherwise rarely occurs, and encourages relying parties that use no such arrangement to ignore it. Its validation steps also permit the original rule, which many libraries still apply: when azp is present, it must equal the relying party's own client ID.

The printer uses no such arrangement, and the photo service's tokens for it carry no azp. Ignoring the claim and applying the original rule lead to the same result for every token the photo service should be sending. The difference appears only if something unexpected arrives, and a token that names a different client as the party it was issued to is not one the printer asked for. So the printer rejects it, and keeps the rule switched on in its library.

The issuer and audience settle whose statement this is and whom it is for. They say nothing about when it was made, or which sign-in attempt it answers.

Try it in the Lab

PUT IT INTO PRACTICE

Check your understanding

Try these questions before moving on. If an answer isn't right, use the feedback and try again.

0 of 2 answered correctly

Enable JavaScript to answer these questions and save progress in this browser.

QUESTION 1 OF 2A hosted sign-in service gives each organization its own issuer on one host and signs every organization's tokens with the same keys. Why is accepting any issuer that starts with the service's address dangerous?

QUESTION 2 OF 2An ID token reaches the printer's backend with a valid signature from the photo service, the right issuer, sub user-2048, and aud photo-collage. What should the printer do?

We value your privacy

We use cookies and similar technologies to enhance your browsing experience, and analytics to understand our traffic. By clicking "Allow All", you consent to optional analytics. Cookie Policy

Learn identity