To add claims, you have to do it from authorization-server (Keycloak in your case), not resource-server (REST API) nor client. This is obvious for JWTs (which are sealed with content signed by authorization-server), but should be respected for introspection too.
Keycloak "mapper"
For Keycloak, private claims are added using "mappers". I have a complete sample in this project.
All you have to do is:
- pull Keycloak dependencies and add maven shade plugin to your build
<dependencies>
<!-- provided keycloak dependencies -->
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi</artifactId>
<version>${keycloak.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi-private</artifactId>
<version>${keycloak.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-services</artifactId>
<version>${keycloak.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<!-- Run shade goal on package phase -->
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
- provide
src/main/resources/META-INF/jboss-deployment-structure.xml
with this content:
<jboss-deployment-structure>
<deployment>
<dependencies>
<module name="org.keycloak.keycloak-services" />
</dependencies>
</deployment>
</jboss-deployment-structure>
- provide
src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper
with a content like (replace with your own mapper implementation):
com.c4_soft.user_proxies.api.keycloak.ProxiesMapper
- provide just above referenced mapper implementation using Keycloak base class and interfaces you need (
OIDCAccessTokenMapper
to add claims to access-tokens is probably a minimum in your case):
public class ProxiesMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper { }
- package and deploy to Keycloak
providers
directory (might need to run keycloak with build
arg once as instructed in providers folder README)
- configure your new mapper from Keycloak administration UI (for the realm or individual clients)
Parsing private claims in Spring
You can access all claims, including privates ones, from spring default Authentication implementations: JwtAuthenticationToken::getTokenAttributes
(for JWT decoder) and BearerTokenAuthentication::getTokenAttributes
(for introspection). Both return a Map<String, Object>
you can use in security expressions.
You can also provide your own Authentication
in place of Spring default ones and parse private claims there (return something more usefull than Object
for the claims you use). Switching Authentication implementation is done the same way as switching authorities mapping:
http.oauth2ResourceServer().jwt().jwtAuthenticationConverter(...)
or
http.oauth2ResourceServer().opaqueToken().authenticationConverter(...)
I have a set of 3 tutorials which incrementally explain how to easily parse (and use in security expression) such private claims: https://github.com/ch4mpy/spring-addons/tree/master/samples/tutorials
Those tutorials are for servlets. If you are writing reactive applications, follow the tutorials and then refer to one of the samples matching your exact configuration