MicroProfile JWT Authentication
JWT bearer auth with @LoginConfig, claim injection, and role-based access.
# CLAUDE.md — MicroProfile JWT Authentication
## Setup
- Add the MP-JWT spec to your runtime (Quarkus: `quarkus-smallrye-jwt`; Open Liberty: bundled).
- On the application class:
```java
@LoginConfig(authMethod = "MP-JWT", realmName = "myapp")
@ApplicationPath("/")
public class App extends Application {}
```
- Configure the public key for verification:
```
mp.jwt.verify.publickey.location=https://auth.example.com/.well-known/jwks.json
mp.jwt.verify.issuer=https://auth.example.com
mp.jwt.verify.audiences=myapp
```
## Securing endpoints
- Use Jakarta Security annotations:
```java
@GET @RolesAllowed("user")
public List<Order> myOrders() { ... }
@POST @RolesAllowed("admin")
public void deleteUser(@PathParam("id") String id) { ... }
```
- `@PermitAll` on public endpoints — be explicit so future developers don't break it accidentally.
- `@DenyAll` on placeholder methods you haven't authorized yet.
## Reading claims
- Inject the full token: `@Inject JsonWebToken jwt`.
- Inject specific claims:
```java
@Inject @Claim("email") String email;
@Inject @Claim("groups") Set<String> groups;
@Inject @Claim("sub") String userId;
```
- Standard claims: `iss`, `sub`, `aud`, `exp`, `iat`, `groups`. Custom claims work the same way.
## Roles
- The `groups` claim is mapped to roles by default. Configure the claim name if your provider uses a different name:
```
mp.jwt.claim.roles.path=resource_access.myapp.roles
```
- Don't trust the token blindly. Validate signature, issuer, audience, expiry. The library does this; just configure correctly.
## Token issuance
- MP-JWT specifies the **verification** side — issuance is up to your auth provider (Keycloak, Auth0, Okta, AWS Cognito).
- For dev, use **smallrye-jwt-build** to issue tokens locally. Never use it in production.
- Pin the JWKS URL to a fixed location — don't accept arbitrary issuers.
## Token transport
- Standard `Authorization: Bearer <token>` header.
- For browser apps, store in HttpOnly Secure cookies. The MP-JWT extension can read from cookies if configured:
```
mp.jwt.token.header=Cookie
mp.jwt.token.cookie=jwt
```
- Never store JWTs in `localStorage`.
## Refresh
- MP-JWT doesn't define refresh. Implement at the auth provider — clients send refresh tokens to the auth server, get fresh access tokens.
- Keep access tokens short-lived (15 min). Refresh tokens longer-lived but revocable server-side.
## Don't
- Don't put sensitive data (PII, plan info) in JWT claims. The token is base64url-decodable by anyone.
- Don't accept tokens without verifying the signature.
- Don't use `@RolesAllowed` and ignore object-level authorization. JWT proves identity; ownership checks happen in the service.
- Don't issue long-lived (months) access tokens to "avoid" refresh complexity.
Other MicroProfile templates
MicroProfile Core Rules
MicroProfile Config, Health, Metrics — opinionated cloud-native Java defaults.
MicroProfile REST Client
Type-safe REST clients with @RegisterRestClient, async, and exception mapping.
MicroProfile Fault Tolerance
Retries, circuit breaker, timeout, bulkhead, fallback — patterns and gotchas.
MicroProfile OpenAPI
OpenAPI 3 documentation with annotations, schemas, and operation metadata.