JWT
This page details JWT.
Runtime Dependency
<dependency>
<groupId>io.yupiik.fusion</groupId>
<artifactId>fusion-jwt</artifactId>
<version>${fusion.version}</version>
</dependency>
Configuration
The configuration is a JwtValidatorConfiguration (you have to integrate it in your application configuration or reuse the jwt named one you can inject). Here are the subkeys:
| Key | Default | Description |
|---|---|---|
|
|
required |
The public/private key used to validate. |
|
|
|
The signature algorithm. |
|
|
- |
The expected issuer. |
|
|
|
Clock tolerance in seconds. |
|
|
|
Whether the JWT ID is required. |
|
|
|
Whether the expiration is required. |
|
|
|
Whether the issued-at is required. |
|
|
|
Whether the not-before is required. |
|
|
- |
A JWKS list of keys ( |
The signer side uses a JwtSignerConfiguration with jwt-signer.* keys (key required, algorithm RS256, issuer required, kid k001, expRequired true, expValidity, iatRequired false, nbfRequired false).
Usage
Entry point is to inject a JwtValidatorFactory (through constructor or @Injection on a field) and create an instance of validator passing a JwtValidatorConfiguration which sets the JWT algorithm, issuer, key etc...
@ApplicationScoped
public class MyService {
private final Function<String, Jwt> jwtValidator;
protected MyService() {
// no-op, for application scoped proxy
}
public MyService(final JwtValidatorFactory jwtValidatorFactory, final MyAppConfig config) { (1)
this.jwtValidator = jwtValidatorFactory.newValidator(config.jwt()); (2)
}
public Optional<Jwt> findJwt(final Request request) { (3)
final var jwt = request.header("authorization");
if (jwt == null || !jwt.startsWith("Bearer ")) {
return empty();
}
try {
return jwtValidator.apply(jwt.substring("Bearer ".length()));
} catch (final RuntimeException re) {
// depending your code you can log the error or not but generally good to log it
return empty();
}
}
}
- Inject the validator factory and the JWT validator configuration (key, algorithm, ...),
- Create the runtime validator (once for the app),
- If the JWT header is present extract it (or fail with an exception if invalid).
Integration with web layer
For JSON-RPC module, the easiest integration is to observe io.yupiik.fusion.jsonrpc.event.BeforeRequest event and plug your validation logic there (claim checks for example):
// jwtValidator as in MyService
public void onJsonRpcJwt(@OnEvent final BeforeRequest event) {
final var jwt = readJwtFromHeaderValue(event.request().header("authorization")); // (1)
final var validated = jwtValidator.apply(jwt); (2)
if (!validated
.map(ok -> ok.claim("roles", List.class).contains("admin")) (3)
.orElse(true)) {
(4)
final var failed = new CompletableFuture<Response>();
failed.completeExceptionally(new JsonRpcException(...)); // set your code, message, data
event.promises().add(failed);
}
}
-
Like in
MyService(previous snippet), extract the jwt from the header checking/droppingBearerprefix, - Validate the JWT,
-
Check
rolesclaim containsadmin, - Complete the request as failed (all requests if bulk is used).
|
TIP
|
if you don't want to redefine the configuration nor the validator, you can inject |