Java SDK — Overview
authorization-core is a Java SDK that adds declarative @Resource-based access control to Spring Boot and Quarkus services via AOP and CDI interception.
Edit this page on GitHubauthorization-core (io.gitlab.ctu-iotlab:com.authorization.core) is a Java 17 library that integrates Permix into your JVM microservices. It provides:
- A
@Resourceannotation you place on any method or class - An interceptor (Spring AOP / Quarkus CDI) that calls Permix before every annotated invocation
- A startup initializer that auto-registers all discovered resources on boot
- Framework auto-configuration for Spring Boot and Quarkus — zero boilerplate
Auto-configuration, AOP aspect, RequestScope header extraction.
CDI interceptor, MicroProfile Config, Startup bean.
Maven dependency#
<dependency>
<groupId>io.gitlab.ctu-iotlab</groupId>
<artifactId>com.authorization.core</artifactId>
<version>0.1.5</version>
</dependency>Published to Maven Central under the MIT License. Requires Java 17+.
The @Resource annotation#
@Inherited
@InterceptorBinding // CDI binding
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Resource {
String name() default ""; // unique key, e.g. "invoice:read"
String displayName() default ""; // human-readable label
String[] defaultRoles() default {}; // roles bootstrapped on first registration
}@Resource can be placed on a method (recommended) or a class (applies to all methods). In Quarkus, the interceptor checks the method annotation first and falls back to the class annotation.
How it works at runtime#
Every time an annotated method is called, the interceptor:
- Reads all inbound HTTP request headers via
HeaderExtractor. - Strips restricted headers (
connection,host,content-length,expect,upgrade,transfer-encoding) viaHeaderSanitizer. - Forwards the sanitized headers plus calls
POST /resources/access/checkwith{"name": "<resource-name>"}. - If the response is
{"authorized": false}or the request fails → throwsSecurityException→ interceptor turns it into HTTP 403. - If
enabled = falsein config → the check is skipped entirely (method proceeds normally).
Inbound Request
│
▼
HeaderExtractor ──► HeaderSanitizer ──► GenericRestClient
│
POST /resources/access/check
{"name": "invoice:read"}
│
{"authorized": true/false}
│
┌───────────────┴───────────────┐
allowed denied
│ │
proceed() SecurityException → 403Startup resource registration#
On application startup, ResourceInitializer discovers every @Resource-annotated method in your codebase and registers them with Permix so that roles and policies can be managed centrally.
Registration flow:
SpringInitialize/QuarkusInitializeruns@PostConstruct.ResourceCollectorAdapter.collect()scans all beans/CDI beans for@Resourcemethods.- Calls
TokenProvider.getAdminToken()→ performsclient_credentialstoken exchange against{AUTH_SERVER_URL}/protocol/openid-connect/token. - Calls
POST /resources/listwith all discovered resources in one batch.
Self-skip guard
If ctu.iotlab.resource-config.service-name equals ctu-resource-management-service (the Permix itself), the initializer skips registration to prevent a bootstrap loop.
Registration payload sent per resource:
{
"name": "invoice:read",
"displayName": "Read Invoice",
"serviceName": "invoice-service",
"defaultRoles": ["finance", "admin"]
}Configuration reference#
All keys are read through ApplicationConfigProvider (Spring Environment or MicroProfile Config).
| Property key | Required | Description |
|---|---|---|
ctu.iotlab.resource-config.url | ✅ | Base URL of Permix |
ctu.iotlab.resource-config.service-name | ✅ | Logical name of this microservice |
ctu.iotlab.resource-config.enabled | ✅ | true to enable enforcement; any other value disables all checks |
ctu.iotlab.resource-config.client-secret | — | OAuth2 client secret (fallback if ADMIN_CLIENT_SECRET env var not set) |
ctu.iotlab.resource-config.dev-mode | — | Not read directly; dev mode is detected from the active Spring/Quarkus profile |
Environment variables (read via System.getenv):
| Env var | Default | Description |
|---|---|---|
ADMIN_CLIENT_ID | iotlab-admin | OAuth2 client ID for token exchange |
ADMIN_CLIENT_SECRET | (from client-secret property) | OAuth2 client secret |
Framework-specific OIDC URL keys (used by TokenProvider):
| Framework | Property key |
|---|---|
| Quarkus | quarkus.oidc.auth-server-url |
| Spring Boot | spring.security.oauth2.resourceserver.jwt.issuer-uri |
The token URL is constructed as {AUTH_SERVER_URL}/protocol/openid-connect/token.
Dev mode#
Dev mode is detected automatically from the active profile — no explicit property needed:
| Framework | Dev mode condition |
|---|---|
| Spring Boot | Active profiles contain "dev" (spring.profiles.active=dev) |
| Quarkus | Active profiles contain "dev" (quarkus dev sets this automatically) |
In dev mode:
- Startup registration is skipped — a log message is printed instead.
- Runtime checks still run (enforcement is controlled by
ctu.iotlab.resource-config.enabled, not the profile).
To also disable runtime checks in development, set ctu.iotlab.resource-config.enabled=false.
Logging#
The SDK uses System.out.println with a structured log format (no SLF4J/Log4j dependency required):
2025-09-10 08:00:00,123 INFO [com.ctu.iotlab] (main) Resource sync process started. Activated profile dev.
2025-09-10 08:00:00,456 INFO [com.ctu.iotlab] (main) Scanned 12 resources.On incomplete token config (missing tokenUrl, clientId, or clientSecret), a WARN line is printed listing the missing fields and registration is skipped gracefully.
Changelog#
| Version | Date | Notes |
|---|---|---|
| 0.2.0 | 2025-10-15 | Removed hard Keycloak dependency; service API key auth for resource registration |
| 0.1.5 | 2025-09-10 | Fixed wrong active-profile detection |
| 0.1.4 | 2025-08-31 | Enhanced Spring exception handling; improved application.properties reading |
| 0.1.0 | 2025-07-20 | Bulk resource registration via POST /resources/list |
| 0.0.1 | 2025-06-01 | Initial release — @Resource annotation, single resource registration |