Provide production-grade stateless authentication and authorization for Spring REST APIs using signed JWT bearer tokens and Spring Security Resource Server.
When to Use
Use when:
API clients authenticate with Authorization: Bearer <token>
server must remain stateless (SessionCreationPolicy.STATELESS)
service acts as an OAuth2 resource server (token consumer), not a login form app
Do not use for SSR/session-first applications.
Security Baseline (Mandatory)
Configure SecurityFilterChain with:
explicit public endpoints first (/actuator/health, auth bootstrap endpoints, API docs when required)
1---2name: spring-rest-auth-jwt3description: Skill: spring-rest-auth-jwt4---5# Skill: spring-rest-auth-jwt67## Type8feature910## Requirements1112- spring-rest-api1314## Conflicts1516- spring-mvc-auth-session1718---1920## Purpose2122Provide production-grade stateless authentication and authorization for Spring REST APIs using signed JWT bearer tokens and Spring Security Resource Server.2324---2526## When to Use2728Use when:29- API clients authenticate with `Authorization: Bearer <token>`30- server must remain stateless (`SessionCreationPolicy.STATELESS`)31- service acts as an OAuth2 resource server (token consumer), not a login form app3233Do not use for SSR/session-first applications.3435---3637## Security Baseline (Mandatory)3839- Configure `SecurityFilterChain` with:40 - explicit public endpoints first (`/actuator/health`, auth bootstrap endpoints, API docs when required)41 - `.anyRequest().authenticated()` last42 - `.oauth2ResourceServer(oauth2 -> oauth2.jwt(...))`43- Set stateless sessions:44 - `session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)`45- Use bearer tokens in headers only. Do not use query params for tokens.46- Keep HTTPS mandatory in all non-local environments.4748---4950## Entry Points5152- Configure `SecurityFilterChain` as the primary security entry point.53- Configure `JwtDecoder` bean for token validation.54- Configure `application.yml` for `issuer-uri` or `jwk-set-uri`.5556---5758## Configuration File Policy5960- Use `application.yml` as the canonical Spring Boot config format.61- Use profile-specific `application-<profile>.yml` files when needed.62- Do not introduce `application.properties` for new configuration.63- Do not keep both `.properties` and `.yml` in the same module because precedence can hide misconfiguration.6465---6667## JWT Validation Rules (Mandatory)6869- Validate signature using trusted keys (`issuer-uri` or `jwk-set-uri`).70- Validate issuer (`iss`) with `JwtValidators.createDefaultWithIssuer(...)`.71- Validate timestamps (`exp`, `nbf`) and preserve clock skew tolerance (default 60s unless policy requires otherwise).72- Add audience (`aud`) validation for API-specific tokens.73- Reject unsigned tokens and weak/unsafe algorithms.7475Use a custom `JwtDecoder` with `DelegatingOAuth2TokenValidator` when audience or custom claim policy is required.7677```java78@Bean79JwtDecoder jwtDecoder(@Value("${security.jwt.issuer-uri}") String issuer) {80 NimbusJwtDecoder decoder = (NimbusJwtDecoder) JwtDecoders.fromIssuerLocation(issuer);8182 OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuer);83 OAuth2TokenValidator<Jwt> audience = new JwtClaimValidator<List<String>>(84 "aud", aud -> aud != null && aud.contains("api://spring-skills")85 );86 OAuth2TokenValidator<Jwt> validator = new DelegatingOAuth2TokenValidator<>(withIssuer, audience);8788 decoder.setJwtValidator(validator);89 return decoder;90}91```9293---9495## Claims and Authorities Mapping9697- Default scope mapping (`scope` / `scp`) to `SCOPE_*` authorities is acceptable for simple APIs.98- For role-based checks, configure a `JwtAuthenticationConverter` explicitly.99- Keep one canonical claim for roles/scopes (avoid mixed claim contracts across issuers).100- Enforce least privilege at endpoint and method layers (`@PreAuthorize` where appropriate).101102---103104## Token and Key Management105106- Prefer asymmetric algorithms (`RS256`/`ES256`) for distributed systems.107- Prefer `issuer-uri` when OIDC discovery is available.108- Use `jwk-set-uri` when discovery is unavailable or startup dependency on issuer metadata must be reduced.109- Allow key rotation through JWK retrieval; do not hardcode static public keys unless required by infrastructure constraints.110- Never log raw JWTs, secrets, or full claims payloads in production logs.111112---113114## CSRF and CORS Guidance115116- For pure bearer-token APIs that do not use cookie/session authentication, disabling CSRF is acceptable.117- If browser cookie auth or cookie-based token transport is introduced, re-evaluate and enable CSRF protections.118- Configure CORS explicitly (allowed origins, methods, headers, credentials policy) for browser clients.119120---121122## Endpoint Policy Defaults123124- Public (explicit allowlist only):125 - health and readiness endpoints required by operations126 - token issuance/refresh endpoints only when this service owns auth flows127- Protected:128 - all business endpoints by default129- Deny by default:130 - everything not explicitly allowed131132---133134## Testing and Verification (Required)135136When security config changes, add/maintain tests that verify:137- Missing/invalid/expired token -> `401`.138- Valid token without required scope/role -> `403`.139- Valid token with required scope/role -> success (`200/2xx`).140- Public endpoints remain reachable without auth.141- Protected endpoints never become anonymously accessible.142143Prefer integration tests with `spring-security-test` JWT support and explicit authority assertions.144145---146147## Output (Required)148149The implementation MUST include:150151- `SecurityConfig` class with `SecurityFilterChain` bean152- `application.yml` properties for JWT configuration153- `JwtDecoder` bean (custom when audience validation is required)154- At least one protected controller endpoint155- Optional: `JwtAuthenticationConverter` when roles are used156157---158159## Anti-Patterns160161- Do NOT mix session-based auth with JWT resource-server flows in the same API surface without explicit architecture.162- Do NOT trust JWT claims without signature and issuer validation.163- Do NOT disable validation checks (`iss`, `exp`, `nbf`, `aud`) for convenience.164- Do NOT store access tokens in local storage for browser apps handling sensitive data.165- Do NOT put tokens in URLs or application logs.166- Do NOT rely on defaults when custom claim mapping is required by your authorization model.167168---169170## References (Context7-aligned)171172- Spring Security Resource Server JWT (servlet): https://docs.spring.io/spring-security/reference/6.5/servlet/oauth2/resource-server/jwt.html173- Spring Security CSRF guidance (servlet): https://docs.spring.io/spring-security/reference/6.5/servlet/exploits/csrf.html174- Spring Boot OAuth2 Resource Server JWT properties: https://docs.spring.io/spring-boot/docs/3.4.1/reference/htmlsingle/#web.security
Run npx skillmds@latest add carlnaddy/spring-rest-auth-jwt in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
Skill: spring-rest-auth-jwt It is listed under Integrations & APIs on SkillMD.
This skill has not completed SkillMD's automated safety review yet. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Yes. Installing skills from SkillMD is free, and the skill stays under its author's original license.
CarlNaddy (@carlnaddy) published this skill. Their other Agent Skills are listed on their SkillMD profile.