Choosing which messages to protect
All domains, identifiers, and tokens in these examples are fictional.
Before launching the student discount, the printing company asks for a security review of its sign-in. The reviewer follows each message from where it is created to every place it is read, and two findings stand out.
The first is the authentication request. When you choose the discount, it carries a claims parameter asking for your Northfield enrollment status, and it travels through your browser's address bar, its history, any extension allowed to read page addresses, and the photo service's request logs. Anyone who sees it learns that the printer asked whether you are a student. The second is the UserInfo response. HTTPS protects it only as far as the hosting company's load balancer, where the connection ends. From there it crosses the printer's internal network to the sign-in service, and your name, email address, and student status are then passed on to a separate order service, which has to take the sign-in service's word for where they came from.
Messages that can be protected
OpenID Connect allows four of its messages to be signed with JSON Web Signature (JWS), encrypted with JSON Web Encryption (JWE), or both: the ID token, the UserInfo response, the request object, and the JWT a client uses to authenticate itself. Related specifications protect others in the same way, such as JARM for authorization responses. The defaults differ:
| Message | Created by | By default | Can also be |
|---|---|---|---|
| Authentication request | The printer | Plain parameters in the browser's address | A request object, signed by the printer, encrypted to the photo service, or both |
| Authorization response | The photo service | Plain parameters in the redirect | Signed, and optionally encrypted to the printer, with JARM |
| ID token | The photo service | Signed, apart from one narrow case | Also encrypted to the printer |
| UserInfo response | The photo service | Plain JSON | Signed, encrypted to the printer, or both |
| Client assertion | The printer | Used only with JWT-based client authentication | Always signed when used, and can also be encrypted |
A message is signed with its creator's private key and encrypted with its reader's public key. The specifications also allow keys based on a confidential client's secret, but a shared secret cannot show which of the two sides produced a message, so this group uses key pairs throughout. The JAR lessons and JARM lessons in Advanced OAuth applied these protections to requests and authorization responses. This group applies them to the messages OpenID Connect adds.
What a signature adds
Each protection should answer a question that someone actually needs answered. For a signature, the question is who needs to check where a message came from, and when.
For the ID token, the specification has already answered: ID tokens are signed. The one unsigned case, which Signing keys and rotation described, needs a client that registered for it, and the printer never has. A UserInfo response usually is not signed at all. The printer requests it directly over HTTPS with its own access token, and checks that its sub matches the ID token. That connection shows the answer came from the photo service, but it shows this only to the sign-in service, and only while the connection lasts. The order service in the reviewer's second finding never saw that connection. If the photo service signs the response, the sign-in service can pass the signed JWT along, and the order service can verify it with the photo service's public key without trusting anything in between. A signed UserInfo response must also contain iss and aud, so the order service can check that it was the photo service's statement, made for the printer.
For the request, the reasoning runs the other way: the photo service is the one that needs to know the request is genuine. OpenID Connect's security considerations note that parameters such as max_age and acr_values give the provider more assurance about the authentication being requested when they arrive in a signed request, and the claims parameter is no different. The printer still checks auth_time and acr in the ID token itself, as Session age and reauthentication and Authentication context and methods taught. The JAR lessons covered what a signed request object proves and how a provider validates one.
What encryption adds
For encryption, the question is who can read a message between the moment it is created and the moment its intended reader opens it.
The request object passes through the browser, which is exactly where the reviewer's first finding arose. Signing it hides nothing, because anyone holding a signed JWT can decode it. OpenID Connect's security considerations describe this case: knowing that a client asked for a particular claim, or a particular authentication method, can itself reveal something about the person. Encrypted to the photo service's public key, the request object keeps the claims request out of the address bar, history, and logs, in a form only the photo service can open. Sending the object by reference, or pushing it with PAR, also keeps it out of the address bar. Encryption protects its contents wherever it is stored or passed along.
The ID token is a different case. With the code flow, it travels directly from the token endpoint to the printer's backend over HTTPS, and in the running example it contains no profile claims at all. Encryption matters more where an ID token passes through the browser, as it does in the implicit and hybrid flows covered in Understanding implicit and hybrid integrations, or where a provider places sensitive claims in it. One detail catches out relying parties that do receive encrypted ID tokens. To send one later as an id_token_hint, the relying party must decrypt it and send the signed token inside, which it may encrypt again to the provider's own key.
The UserInfo response was the reviewer's second finding. Encrypted to the printer's public key, it stays unreadable from the moment the photo service sends it until it reaches the one component that holds the printer's private key, past the load balancer, the internal network, and anything along the way that records request or response bodies.
Encryption has limits. Anyone can encrypt to a public key, so an encrypted message on its own says nothing about who wrote it, and encryption does nothing to stop a copied message being delivered again. It also hides the contents from the printer's own monitoring, which is sometimes the point and sometimes an obstacle.
The printer's choices
With those questions answered message by message, the printer decides:
| Message | Decision | Reason |
|---|---|---|
| Request object | Signed with printer-2026-10, then encrypted to the photo service, every time | The photo service can rely on what the printer asked for, and nobody along the way can read it. Encrypting only the requests that ask about enrollment would make exactly those requests stand out. |
| Authorization response | Unchanged: a code, state, and iss, with PKCE | It carries nothing worth hiding, and PKCE protects the code. JARM remains available if the printer later wants signed responses. |
| ID token | Signed only | It arrives directly from the token endpoint and contains no profile claims. |
| UserInfo response | Signed, then encrypted to the printer | The order service can verify the signature, and the encryption protects your profile past the load balancer. |
Each choice has a cost. The printer must now publish an encryption key and replace it from time to time, the photo service must support every algorithm the printer picks, and each added layer brings more algorithm combinations that both implementations must support and test. A provider that does not list an encryption algorithm in its metadata cannot be asked to use it. Signing and encryption follows the printer as it registers these choices and opens the first encrypted response.