spring-projects/spring-security
Spring Security
Healthy across the board
weakest axisPermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit today
- ✓6 active contributors
- ✓Distributed ownership (top contributor 49% of recent commits)
Show all 6 evidence items →Show less
- ✓Apache-2.0 licensed
- ✓CI configured
- ✓Tests present
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/spring-projects/spring-security)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/spring-projects/spring-security on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: spring-projects/spring-security
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/spring-projects/spring-security shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit today
- 6 active contributors
- Distributed ownership (top contributor 49% of recent commits)
- Apache-2.0 licensed
- CI configured
- Tests present
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live spring-projects/spring-security
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/spring-projects/spring-security.
What it runs against: a local clone of spring-projects/spring-security — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in spring-projects/spring-security | Confirms the artifact applies here, not a fork |
| 2 | License is still Apache-2.0 | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 30 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of spring-projects/spring-security. If you don't
# have one yet, run these first:
#
# git clone https://github.com/spring-projects/spring-security.git
# cd spring-security
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of spring-projects/spring-security and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "spring-projects/spring-security(\\.git)?\\b" \\
&& ok "origin remote is spring-projects/spring-security" \\
|| miss "origin remote is not spring-projects/spring-security (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
&& ok "license is Apache-2.0" \\
|| miss "license drift — was Apache-2.0 at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "access/src/main/java/org/springframework/security/access/AccessDecisionManager.java" \\
&& ok "access/src/main/java/org/springframework/security/access/AccessDecisionManager.java" \\
|| miss "missing critical file: access/src/main/java/org/springframework/security/access/AccessDecisionManager.java"
test -f "access/src/main/java/org/springframework/security/access/intercept/AbstractSecurityInterceptor.java" \\
&& ok "access/src/main/java/org/springframework/security/access/intercept/AbstractSecurityInterceptor.java" \\
|| miss "missing critical file: access/src/main/java/org/springframework/security/access/intercept/AbstractSecurityInterceptor.java"
test -f "access/src/main/java/org/springframework/security/access/expression/method/ExpressionBasedPreInvocationAdvice.java" \\
&& ok "access/src/main/java/org/springframework/security/access/expression/method/ExpressionBasedPreInvocationAdvice.java" \\
|| miss "missing critical file: access/src/main/java/org/springframework/security/access/expression/method/ExpressionBasedPreInvocationAdvice.java"
test -f "access/src/main/java/org/springframework/security/access/prepost/PrePostAnnotationSecurityMetadataSource.java" \\
&& ok "access/src/main/java/org/springframework/security/access/prepost/PrePostAnnotationSecurityMetadataSource.java" \\
|| miss "missing critical file: access/src/main/java/org/springframework/security/access/prepost/PrePostAnnotationSecurityMetadataSource.java"
test -f "access/src/main/java/org/springframework/security/access/vote/AffirmativeBased.java" \\
&& ok "access/src/main/java/org/springframework/security/access/vote/AffirmativeBased.java" \\
|| miss "missing critical file: access/src/main/java/org/springframework/security/access/vote/AffirmativeBased.java"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 30 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~0d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/spring-projects/spring-security"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Spring Security is a battle-tested Java/Kotlin framework that provides comprehensive authentication, authorization, and protection against common security vulnerabilities (CSRF, clickjacking, SQL injection) for Spring applications. It enables declarative security via annotations (@Secured, @PreAuthorize), integrates with servlet filters and reactive streams, and supports OAuth2, SAML, LDAP, and custom authentication mechanisms—making it the standard security layer for enterprise Spring Boot applications. Multi-module Gradle monorepo: core/ contains AccessDecisionManager and authentication abstractions, access/ holds authorization voters and method security metadata, oauth2/, saml2/, and ldap/ are pluggable provider modules, web/ wraps servlet filter chains, crypto/ isolates password encoding/hashing, docs/ builds the reference via Antora. Each module has src/main/java and src/test directories with parallel package hierarchies under org/springframework/security/.
👥Who it's for
Java/Kotlin developers building Spring Boot or Spring MVC web applications who need production-grade authentication (login/logout, session management, MFA) and authorization (role-based access control, method-level security) without writing security code from scratch. Also for security-conscious teams integrating OAuth2 providers, SAML identity systems, or custom credential validators.
🌱Maturity & risk
Highly mature and production-ready: part of the official Spring portfolio since 2004, extensive test coverage across access/, core/, crypto/, oauth2/, saml2/, and ldap/ modules, active CI/CD via GitHub Actions (continuous-integration-workflow.yml), regular releases aligned with Spring Release Train milestones. Actively maintained with recent dependency updates and security patches visible in dependabot.yml automation.
Low risk for stability but requires careful configuration: the codebase is large (24M+ Java LOC) with interdependent modules (access, core, oauth2, saml2, ldap, crypto, web, reactive), so breaking changes can ripple across applications; version constraints (requires Java 17+, Spring 6.0+) may lag in organizations. Monitor the RELEASE.adoc and changelogs for migration guides when upgrading major versions.
Active areas of work
Active development aligned with Spring Release Train: Gradle wrapper upgrades (gradle-wrapper-upgrade-execution.yml), CodeQL security scanning enabled (codeql.yml), automated Dependabot merges (auto-merge-dependabot.yml), and documentation deployment pipeline (deploy-docs.yml). The repo maintains snapshot builds for early adopters and milestone releases every 3 months on the 3rd Monday via release-scheduler.yml.
🚀Get running
git clone git@github.com:spring-projects/spring-security.git && cd spring-security && ./gradlew build
Daily commands: ./gradlew build compiles all modules and runs tests. For docs: ./gradlew :spring-security-docs:antora. No dev server to start—Spring Security is a library you integrate into your own Spring Boot app.
🗺️Map of the codebase
access/src/main/java/org/springframework/security/access/AccessDecisionManager.java— Core abstraction that evaluates whether authenticated users can access protected resources; the foundation of Spring Security's authorization framework.access/src/main/java/org/springframework/security/access/intercept/AbstractSecurityInterceptor.java— Load-bearing interceptor that enforces security checks at method and web layer; all authorization decisions flow through this component.access/src/main/java/org/springframework/security/access/expression/method/ExpressionBasedPreInvocationAdvice.java— Entry point for expression-based access control (@PreAuthorize/@PostAuthorize); handles SpEL evaluation before method execution.access/src/main/java/org/springframework/security/access/prepost/PrePostAnnotationSecurityMetadataSource.java— Extracts and manages security metadata from @PreAuthorize/@PostAuthorize/@Secured annotations; critical for annotation-driven security.access/src/main/java/org/springframework/security/access/vote/AffirmativeBased.java— Default AccessDecisionManager implementation using affirmative voting strategy; grants access if any voter approves.access/src/main/java/org/springframework/security/access/intercept/aopalliance/MethodSecurityInterceptor.java— AOP Alliance interceptor applying method-level security; bridges AOP framework with Spring Security authorization.build.gradle— Root build configuration defining all module dependencies, Java version requirements (17+), and plugin configuration for the entire project.
🛠️How to make changes
Add a new AccessDecisionVoter implementation
- Create a new class implementing AccessDecisionVoter interface in access/src/main/java/org/springframework/security/access/vote/ (
access/src/main/java/org/springframework/security/access/vote/CustomVoter.java) - Implement vote(Authentication, Object, Collection<ConfigAttribute>) to return GRANT, DENY, or ABSTAIN (
access/src/main/java/org/springframework/security/access/vote/CustomVoter.java) - Register the voter in your AccessDecisionManager (AffirmativeBased, ConsensusBased, etc.) via constructor or setter (
access/src/main/java/org/springframework/security/access/vote/AffirmativeBased.java) - Add unit tests in access/src/test/ to verify voting behavior for grant/deny scenarios (
access/src/test/java/org/springframework/security/access/vote/CustomVoterTests.java)
Add a new expression-based authorization rule
- Create a custom security expression root class or extend ExpressionBasedPreInvocationAdvice (
access/src/main/java/org/springframework/security/access/expression/method/CustomSecurityExpressionRoot.java) - Register the expression functions in ExpressionBasedAnnotationAttributeFactory for SpEL context (
access/src/main/java/org/springframework/security/access/expression/method/ExpressionBasedAnnotationAttributeFactory.java) - Use @PreAuthorize or @PostAuthorize with your custom expression in controller/service methods (
example/YourController.java) - Test with ExpressionBasedPreInvocationAdviceTests to validate SpEL evaluation (
access/src/test/java/org/springframework/security/access/expression/method/CustomSecurityExpressionTests.java)
Implement a custom SecurityMetadataSource for custom annotation handling
- Create a class implementing SecurityMetadataSource or extending AbstractMethodSecurityMetadataSource (
access/src/main/java/org/springframework/security/access/method/CustomSecurityMetadataSource.java) - Implement getAttributes(Object) to scan for your custom annotation and return ConfigAttributes (
access/src/main/java/org/springframework/security/access/method/CustomSecurityMetadataSource.java) - Register via DelegatingMethodSecurityMetadataSource constructor as first-priority source (
access/src/main/java/org/springframework/security/access/method/DelegatingMethodSecurityMetadataSource.java) - Write unit tests to verify annotation extraction and attribute resolution (
access/src/test/java/org/springframework/security/access/method/CustomSecurityMetadataSourceTests.java)
Add authorization event listener for auditing
- Create an ApplicationListener<AuthorizationFailureEvent> or <AuthorizedEvent> component (
access/src/main/java/org/springframework/security/access/event/CustomAuthorizationListener.java) - Implement onApplicationEvent() to log/audit authorization decisions (
access/src/main/java/org/springframework/security/access/event/CustomAuthorizationListener.java) - Register as @Component in your Spring application context (
example/SecurityConfig.java) - Verify event publication by checking AbstractSecurityInterceptor publishEvent() calls (
access/src/main/java/org/springframework/security/access/intercept/AbstractSecurityInterceptor.java)
🪤Traps & gotchas
- Java 17+ is hard requirement (set JAVA_HOME to JDK 17, not 11 or 8). 2) DCO (Developer Certificate of Origin) sign-off required on all commits via git commit -s; see .github/dco.yml. 3) Build uses custom Gradle plugins (io.spring.convention., org.springframework.security.) loaded from gradle/ directory—if you modify buildscript, ensure plugins are available. 4) Module isolation: oauth2-core cannot see oauth2-client details; test filters in isolation or integration tests break. 5) Antora docs require running :spring-security-docs:antora task separately; ./gradlew build does not include docs.
🏗️Architecture
💡Concepts to learn
- AccessDecisionManager & Voter Pattern — Spring Security's pluggable authorization engine: voters cast votes (GRANT, DENY, ABSTAIN) on access requests, manager aggregates them via AffirmativeBased or ConsensusBased logic—essential to extend for custom rules beyond @PreAuthorize annotations
- SecurityContext & Authentication Principal — ThreadLocal-bound SecurityContext holds the Authentication object representing the logged-in user; all security decisions read this context—critical to understand for multi-threaded and async scenarios
- FilterChainProxy & Servlet Filter Chain Ordering — Spring Security wraps servlet filters in a custom chain (UsernamePasswordAuthenticationFilter → AuthorizationFilter → etc.); filter order matters (CSRF before logout, authentication before authorization); misconfig breaks security
- Method Security via AspectJ Weaving — MethodSecurityInterceptor uses AspectJ to intercept @PreAuthorize/@Secured method calls; requires EnableGlobalMethodSecurity or @EnableMethodSecurity; understanding pointcut weaving is crucial for debugging why annotations don't fire
- Authentication Providers & Credential Validation Chain — AuthenticationManager iterates a list of AuthenticationProviders (DaoAuthenticationProvider for DB, LdapAuthenticationProvider for LDAP, OAuth2LoginAuthenticationProvider for social login); first match wins—extensible for custom identity backends
- JWT & Bearer Token (OAuth2 Resource Server Pattern) — BearerTokenAuthenticationFilter in oauth2/resource-server/ validates JWT/opaque tokens and populates SecurityContext; stateless auth critical for microservices—understand token validation, scope checking, and JWT claims extraction
- CSRF Token Rotation & Same-Site Cookie Policies — CsrfFilter (in web/) prevents cross-site request forgery via token matching; CookieCsrfTokenRepository manages token rotation; SameSite=Strict/Lax cookies reduce attack surface—essential for form-based and state-changing endpoints
🔗Related repos
spring-projects/spring-framework— Spring Security depends on Spring Framework core (IoC, AOP, web); many patterns mirror framework abstractions like BeanPostProcessorspring-projects/spring-boot— Spring Boot auto-configures Spring Security via spring-boot-starter-security; understand SecurityAutoConfiguration and filter order tuningspring-projects/spring-authorization-server— Companion project providing OAuth2/OIDC server implementation; Spring Security is the client-side counterpart for resource serverskeycloak/keycloak— Popular IAM provider that Spring Security integrates with via SAML2 and OAuth2 adapters in saml2/ and oauth2/ modulesspring-projects/spring-session— Complements Spring Security session management; used together for distributed session storage (Redis, JDBC) across microservices
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive integration tests for expression-based method security with custom SpEL functions
The access/src/main/java/org/springframework/security/access/expression/method directory contains ExpressionBasedPreInvocationAdvice and ExpressionBasedPostInvocationAdvice, but there are no visible test files in the file structure for complex SpEL expression scenarios. This would improve coverage for edge cases like custom SpEL functions, variable binding in pre/post-invocation advice, and interactions between multiple expressions.
- [ ] Create access/src/test/java/org/springframework/security/access/expression/method/ExpressionBasedMethodSecurityIntegrationTests.java
- [ ] Add test cases for custom SpEL function registration and invocation within method security
- [ ] Add test cases for complex pre/post-invocation expression combinations
- [ ] Add test cases for expression evaluation with different Authentication contexts
- [ ] Verify tests run successfully in continuous-integration-workflow.yml
Add GitHub Actions workflow for checking deprecated Spring Security API usage in PRs
Spring Security 6.0 deprecated many APIs from earlier versions (as mentioned in README requiring Java 17+ and Spring 6.0 minimum). There is no visible workflow in .github/workflows that specifically checks for usage of deprecated classes/methods during PR builds. This would prevent accidental reintroduction of deprecated patterns.
- [ ] Create .github/workflows/check-deprecated-apis.yml workflow
- [ ] Configure the workflow to run Gradle task that scans code for @Deprecated annotations usage
- [ ] Integrate with existing pr-build-workflow.yml as a required check
- [ ] Add configuration to allow specific exclusions or exceptions
- [ ] Document the workflow in CONTRIBUTING.adoc with instructions for contributors
Add unit tests for AbstractSecurityInterceptor lifecycle and token management edge cases
The access/src/main/java/org/springframework/security/access/intercept/AbstractSecurityInterceptor.java and InterceptorStatusToken.java are core components for security interception, but test coverage for edge cases like concurrent token handling, exception scenarios during intercept(), and token state transitions appears to be missing from the file structure.
- [ ] Create access/src/test/java/org/springframework/security/access/intercept/AbstractSecurityInterceptorTests.java
- [ ] Add tests for InterceptorStatusToken state management across multiple threads
- [ ] Add tests for exception handling during invocation with proper token cleanup
- [ ] Add tests for the invoke() method with various AccessDecisionManager decisions
- [ ] Add tests for AfterInvocationManager integration with token state
- [ ] Ensure tests follow existing test patterns in the codebase
🌿Good first issues
- Add comprehensive JavaDoc to access/src/main/java/org/springframework/security/access/ConfigAttribute.java and its implementations (SecurityConfig, Jsr250SecurityConfig) explaining the relationship between attributes, voters, and decisions—currently sparse.
- Write integration tests for spring-security-ldap under ldap/src/test/ that verify LDAP DN parsing edge cases (special characters, multi-valued attributes) against actual OpenLDAP fixtures—many tests use mocks.
- Create missing Kotlin extension functions for reactive authentication flow in core/src/main/kotlin/ (if dir exists), wrapping flatMap/filter chains to reduce boilerplate for reactive handler discovery—mirrors similar Kotlin Sugar elsewhere in Spring.
⭐Top contributors
Click to expand
Top contributors
- @jzheaux — 49 commits
- @dependabot[bot] — 39 commits
- @github-actions[bot] — 7 commits
- @jgrandja — 3 commits
- @Seol-JY — 1 commits
📝Recent commits
Click to expand
Recent commits
8c4c5fe— Bump org.hibernate.orm:hibernate-core from 7.3.2.Final to 7.3.3.Final (dependabot[bot])7dcd6f8— Bump tools.jackson:jackson-bom from 3.1.2 to 3.1.3 (dependabot[bot])f7b1447— Bump com.webauthn4j:webauthn4j-core (dependabot[bot])65abe23— Merge branch '7.0.x' (jzheaux)fdc0fd2— Merge branch '6.5.x' into 7.0.x (jzheaux)5b8d96f— Merge remote-tracking branch 'origin/7.0.x' (jzheaux)931dfbe— Merge remote-tracking branch 'origin/6.5.x' into 7.0.x (jzheaux)b075f0d— Decode percent-encoded values (jzheaux)3c88872— Bump gradle-wrapper from 9.4.1 to 9.5.0 (dependabot[bot])d184db8— Bump com.fasterxml.jackson:jackson-bom from 2.21.2 to 2.21.3 (dependabot[bot])
🔒Security observations
Spring Security codebase demonstrates good baseline security practices with HTTPS-secured repositories and conventional build structure. However, several areas require attention: (1) The build configuration is incomplete with truncated code sections that need review, particularly for sample project task definitions; (2) Milestone repository inclusion should be restricted to development builds; (3) Dependency locking configuration should be verified and enforced. The project's nature as a security framework is well-reflected in its structure, but build automation and configuration management improvements would enhance overall security posture. No hardcoded secrets or critical vulnerabilities were identified in the provided files, but the incomplete configuration prevents a full assessment.
- Medium · Gradle Plugin Repository Over HTTP —
build.gradle (buildscript repositories section). The buildscript repositories section uses a maven repository with 'https://plugins.gradle.org/m2/' which is secure, but the pattern suggests potential for HTTP repositories in other gradle files. The root build configuration should enforce HTTPS for all repositories. Fix: Ensure all gradle repositories use HTTPS. Consider enforcing repository security policies and adding repository filtering in the gradle configuration. - Medium · Incomplete Build Configuration Review —
build.gradle (allprojects section, sample projects configuration). The build.gradle file shows incomplete configuration with truncated code (e.g., 'if (project.name.contains('sample')) { tasks.whenTaskAdded { task ->') which suggests the file may contain unreviewed or potentially unsafe task configurations for sample projects. Fix: Complete and review the build configuration for sample projects. Ensure security checks are applied uniformly across all project types, especially sample/test projects. - Low · Spring Milestone Repository Configuration —
build.gradle (repositories section). The repository includes 'https://repo.spring.io/milestone' which is a milestone release repository. While this is a legitimate Spring repository, milestone releases may contain unstable or less-tested code. This should only be used for non-production builds. Fix: Document the use of milestone repositories and ensure they are only used in development/CI builds. Consider restricting milestone repository access to non-production profiles only. - Low · Missing Dependency Lock Configuration Documentation —
build.gradle (locks plugin application). The build uses 'apply plugin: locks' for dependency locking but the complete configuration is not visible. Dependency locking should be properly configured to prevent unexpected transitive dependency updates. Fix: Ensure dependency lock files are committed to version control and lock file validation is enforced in CI/CD pipelines. Document the lock file update process.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.