Skip to main content

Resource Server

Chapter 1

We'll start with a very simple Spring Boot application acting as a Resource Server, secured by Keycloak. It will only perform authentication (i.e., verify the JWT token is valid and issued by our Keycloak instance) but not authorization (i.e., check specific roles or permissions yet).

Keycloak Configuration for Realm And Client

Realm config details: Realm

Variable nameValue
Realm namemy-spring-realm
Client IDspring-resource-server
Screenshot 1
Screenshot 2
Screenshot 3
Screenshot 4
Screenshot 5
Screenshot 6
Screenshot 7

User Creation

User config:

Variable nameValue
Usernametestuser
Passwordpassword
Screenshot 1
Screenshot 2
Screenshot 3
Screenshot 4

Get Keycloak Issuer URL and JWKS URI:

Screenshot 1
Screenshot 2
Screenshot 3

Web Security Config

Loading...

Application properties

Loading...

Get a Token with Postman

Postman parameters are ok, however you will get 'Account not fully setup' error. This is because password for user was set as 'Temporary'. Once this is updated, you can acquire 'access_token'

Screenshot 1
Screenshot 2
Screenshot 3

Aud claim

In the application.properties we have

spring.security.oauth2.resourceserver.jwt.audiences=spring-resource-server

But when you check the claim 'aud' in access_token you will notice is set to account. In order to fix it you need to add Dedicated Client Scope with token mapper to Audience claim

Understanding the aud (Audience) Claim:

  • The aud claim in a JWT identifies the intended recipient(s) of the token.
  • A Resource Server (your Spring Boot app) should validate that it is an intended audience for any token it accepts. This prevents a token issued for one service from being replayed against another.
  • The aud claim can be a single string or an array of strings if the token is intended for multiple audiences.

Why is account value for aud claim?

When you used the password grant (grant_type=password) with client_id=spring-resource-server and scope=openid, Keycloak, by default for this flow and client configuration, issued a token whose primary audience is the account client.

Imagine you go to a ticket counter (Keycloak's token endpoint) and say, "I'm spring-resource-server (the client), and here's testuser's ID and password. I want an openid ticket (scope)." Keycloak's default thought process for this specific scenario is something like: "Okay, spring-resource-server wants to help testuser do something related to their account (because of openid). The main place for account stuff is the account service. So, this ticket is primarily for the account service."

It doesn't automatically assume the ticket is only for spring-resource-server to use for its own protected resources unless you explicitly state that spring-resource-server is the intended audience. This behavior encourages more explicit configuration for resource server audience validation, which is a good security practice. It forces you to define which resource servers are meant to consume which tokens.

Screenshot 1
Screenshot 2
Screenshot 3
Screenshot 4
Screenshot 5
Screenshot 6
Screenshot 7