In this tutorial, you will learn how to get the currently authenticated principal user UserId value from the JWT access token generated by Keycloak.
For video lessons on how to secure your Spring Boot application with OAuth 2.0. and Spring Security 5, please checkout my complete video course OAuth 2.0. in Spring Boot applications.
UserId in JWT
The userId value will be stored under the “sub” key in the JWT access token generated by Keycloak. Below is an example of a decoded JWT access token containing the “sub” key.
{ "exp": 1596639645, "iat": 1596639345, "auth_time": 1596639333, "jti": "3e64415f-711b-49f0-a243-8d87e7dbb9f5", "iss": "http://localhost:8080/auth/realms/appsdeveloperblog", "aud": "photo-app-code-flow-client", "sub": "5f3fb480-f86c-4514-8d23-ca88d66c6253", "typ": "ID", "azp": "photo-app-code-flow-client", "session_state": "506b6d80-fc60-4b93-bf4f-7cf057290094", "acr": "1", "email_verified": false, "name": "Sergey Kargopolov", "preferred_username": "sergey.kargopolov", "given_name": "Sergey", "family_name": "Kargopolov", "email": "[email protected]" }
The “sub” key stands for “subject” and will contain the value of currently authenticated principal userId.
Reading UserId from JWT
You can read the userId(JWT subject) value of the currently authenticated user in your Spring Boot web service endpoint with the help of @AuthenticationPrincipal annotation.
Below is an example of a very simple web service endpoint that uses the @AuthenticationPrincipal annotation to inject an instance of Jwt object into a Java method. We can read JWT subject(userId) from the Jwt object the following way.
@DeleteMapping(path = "/{id}") public String deleteUser(@PathVariable String id, @AuthenticationPrincipal Jwt principal) return "Deleted user with id " + id + " and JWT subject " + principal.getSubject(); }
The principal.getSubject() will return the value of the currently authenticated user userId.
Accessing UserId in the Method-Level Security
When using Method-Level Security expressions you can access objects that are injected as method parameters with the help of “#” sign. For example, in the below code snippet, the security expression will validate if the id value provided in the URL path matches the sub value included in the JWT access token.
@PreAuthorize("#id == #principal.subject")
Where:
- #id – is the value provided in the URL request parameter. For example, the /{id} in the following request URL http://localhost:8080/users/5f3fb480-f86c-4514-8d23-ca88d66c6253 will return the 5f3fb480-f86c-4514-8d23-ca88d66c6253.
- The #principal.subject will be the value of userId stored in the JWT access token.
@PreAuthorize("#id == #principal.subject") @DeleteMapping(path = "/{id}") public String deleteUser(@PathVariable String id, @AuthenticationPrincipal Jwt principal) { return "Deleted user with id " + id + " and subject " + principal.getSubject(); }
The code in the above deleteUser() function will be invoked only if the value of “{id}” URL path parameter will be equal to the value of the “sub” key in the JWT access token.
I hope this short tutorial was helpful to you!