The 30 second answer
I keep tokens short-lived with only identity and coarse roles, and every service validates the JWT as a resource server. Fine-grained checks happen at call time, using method security that calls a permission bean. That bean reads current permissions from a central service with a short cache, so a change takes effect within the cache lifetime instead of waiting for the token to expire.
Keep the token short-lived and carry only identity and coarse roles. Each service validates the JWT as an OAuth2 resource server. Fine-grained checks happen at call time with @PreAuthorize calling a bean, for example @PreAuthorize("@perms.canEdit(authentication, #id)"), and that bean reads current permissions from a central service with a short cache. A permission change then takes effect within the cache TTL, not when the token expires. Follow-up: Revoking access right away? (Publish a change event to evict caches; keep token lifetime short.) Editor's note: the central permission service with short caching is a design choice; Spring Security provides the hooks, not the architecture.