A valid signature and trusted issuer do not prove a token was issued for this API.
Spring resource server JWT: validate both issuer and intended audience
Treat audience as a separate check
An identity provider may sign tokens for a warehouse API and a billing API with the same key. The signature and issuer can both validate while the token was meant for billing. Configure the resource server's audience to the warehouse API's identifier. Scope checks still matter, but scope is not a substitute for aud: the recipient and the granted operation are different claims. Resource server setup establishes the filter path.
Make key distribution explicit
A JWK Set URI supplies public verification keys; the resource server must still validate the issuer and audience. Pin accepted signature algorithms and allow a planned key overlap during rotation. Do not fetch a key URL from a token header. The verifier's trusted configuration owns that address. Tenant authorization remains a second check after token validation.
Test rejection, not only admission
Use tokens with the right signature but wrong aud, right aud but wrong iss, expired time, and an unexpected algorithm. Assert 401 for invalid authentication before controller code runs. A successful call with one good token leaves most of the boundary untested.
Implementation sketch
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: ${WAREHOUSE_ISSUER_URI}
audiences: warehouse-ledger-apiCost and verification
JWT verification is local after keys are available, but key retrieval, cache expiry and rotation still need an availability policy. Audience validation adds a small claim check, not a network round trip.
Common Mistakes
- Do not accept a token solely because its signature matches a trusted key.
- Do not confuse an OAuth scope with the API audience.
- Do not trust a JWK Set URL supplied by the token itself.
Read next
Spring Security JWT resource server: validate trust before checking scope, Spring Security JWT tenant principal: map only a validated claim, Spring Security 401 versus 403: authentication and access are separate failures, Test Spring JWT authorization through filters, service proxy and SQL.
