CodeGym /Courses /Spring Security /First introduction to Spring Security

First introduction to Spring Security

Spring Security
Level 1, Lesson 0
Available

1. Five handlers, five trust levels

At the Spring MVC level, all endpoints initially look the same: controller method, annotation, path, HTTP method. But as soon as you look at them through the product lens, they stop being equal. Look at this set of routes:

@GetMapping("/api/public/articles")
@GetMapping("/api/me")
@GetMapping("/api/drafts/{id}")
@PostMapping("/api/editor/drafts/{id}/publish")
@PatchMapping("/api/admin/users/{id}/roles")

For the framework, these are just five handlers. For the business, these are five different trust levels. Public articles should open without a login. The profile of the current user already requires a caller known to the system. A draft by an arbitrary id immediately raises the question of “yours or someone else’s”. Publishing someone else’s content is an editor privilege. Changing roles is a pure administrative zone. One application, one stack, one codebase — but the access logic is already different.

This is a good moment to take the first step toward a security mindset. An endpoint is not just “a piece of business functionality available over HTTP.” It is also a gate into the system, and every gate has access logic. If its meaning is not described explicitly, the system does not become “for now, just without security.” It becomes a system where too much depends on silent assumptions.

2. A quick project audit as an engineering map

To avoid speaking too broadly, it is useful to look at the project through the lens of access right now. Below is not the final configuration and not Spring Security code, but simply an honest audit: what zones actually live inside one API.

Endpoint What it does Access type
GET /api/public/articles returns published articles public
GET /api/me returns the current user’s data authenticated
GET /api/drafts/{id} reads a specific draft owner-only
POST /api/editor/drafts/{id}/publish publishes content after moderation editor
PATCH /api/admin/users/{id}/roles changes a user’s roles admin

The key point here is not the table rows themselves, but the fact that this is one API, not five different systems. Many junior developers first really feel security at exactly this moment: it turns out that “just build CRUD” is not enough, because inside one and the same domain there are simultaneously public scenarios, personal scenarios, ownership rules, and privileged actions.

That is why the course does not start with JWT or a set of annotations. First you need to learn to see the heterogeneity of access inside a regular backend application. Until you can see that, any security framework will seem either like magic or like unnecessary bureaucracy.

3. These zones appear in almost any backend

public appears where the system must be visible from the outside. In our project, that is published articles. If a user just wants to read open content, the backend does not need to interrogate them first. A public zone is not a “hole”; it is a normal part of the product if it is designed deliberately.

authenticated appears where the action no longer makes sense without a user known to the system. A route like /api/me cannot be implemented correctly at all if the system does not understand who is making the request. There still may be no complex role policy here, but the basic requirement is already there: first the system must associate the request with a specific caller.

owner-only appears almost instantly as soon as “my objects” exist in the system: my drafts, my profile, my settings, my files. And this is where the first real engineering insight often happens: the USER role by itself does not solve the problem of “is this my object or someone else’s?”. Two users can have the same role and still not have the right to touch the same data.

editor and admin are not exotic either. As soon as moderation, publishing, a review queue, or managing someone else’s content appears in the system, you get an editor privilege level. As soon as roles, blocking, enabling and disabling accounts, and permission management appear, you are already in the administrative zone. This is not “enterprise horror stories”; it is very ordinary backend product life.

The good news: this pattern repeats from project to project. The bad news is that if you do not learn to notice it early, later you have to fix the consequences with random ifs and comments like // TODO only admin.

4. What you see on /api/me and /api/drafts/{id} 👤

There are two routes where it is especially easy to catch the difference between similar, but not equal, scenarios.

@GetMapping("/api/me")
ProfileDto me() {
    return profileService.currentProfile();
}

@GetMapping("/api/drafts/{id}")
DraftDto one(@PathVariable long id) {
    return draftService.findById(id);
}

/api/me is a self-scoped route. The path itself already hints at it: we are talking about the current user. There is no arbitrary userId that the client brings with them. This is a good design for a personal zone because it reduces the chance of accidentally turning “my profile” into “any profile by id”.

/api/drafts/{id} works differently. Here the client selects a specific object via an arbitrary identifier. And authentication alone is already not enough. It is not enough to know that the caller exists at all. You also need to check whether they have any relation to this object. That is where owner-only appears as a separate type of rule.

It is very useful to keep this distinction in mind from day one. authenticated and owner-only sound similar, but engineering-wise they are different things. In the first case, it is enough to say: “the action is available to a known user.” In the second case, you additionally need to connect the user and the object. That is no longer just a matter of having a role; it is a matter of the relationship between the caller and the data.

5. A five-zone lens for any API

From everything above, you can build a very practical tool. Not a theory “about security in general,” but a small lens that is useful to apply to any endpoint, even if you are not writing Spring Security yet.

Question for the endpoint If the answer is “yes” What it usually means
Can an anonymous client call this action? yes public
Does the action only make sense for a known user? yes at least authenticated
Does the client select a specific object by id or slug? yes check whether owner-only is needed
Does the action affect publishing, moderation, or someone else’s content? yes think about an editor level
Does the action manage users, roles, or system settings? yes this is already admin

This table is intentionally simple. It does not replace the future configuration and does not cover every nuance. But as a first diagnostic filter, it works great. If you run your API through it and almost every endpoint suddenly turns into “well, probably authenticated,” that is almost always a sign that access design has not been thought through yet.

These kinds of small diagnostic lenses are often more useful than “a full glossary of 50 terms.” First you learn to distinguish types of access, and only then do you grow specific mechanics around them. For day one, that is more than enough 🙂

6. Where Spring Security begins

In very short terms: up to this point you learned to build a backend that answers requests. From now on, you learn to build a backend that intentionally chooses whom to answer and under what conditions. In the course lineup, this is a very natural next step: first Spring Boot and basic REST, then the access layer that was missing before.

At the same time, it is important to define the boundaries right away so there are no false expectations. This course does not begin with OAuth2, external identity providers, or a distributed security architecture. First we bring order inside a regular Spring Boot / Spring MVC application. And that is an honest sequence: if you do not see public, authenticated, owner-only, editor, and admin in a simple domain, then advanced topics turn into a set of fashionable words without an internal foundation.

For now, it is enough to keep one thought in mind: in one compact API, five different access zones already live. That means backend security is not “a late checkbox before release,” but part of the architecture from the very beginning.

7. Typical mistakes 🚧

Mistake #1: reducing everything to public and authenticated.
This is often done with the best intentions: you want to quickly split the API into “open” and “closed.” But as soon as the system has “my object,” moderation, or admin actions, such a coarse split starts to lie. It hides the real differences between scenarios and makes dangerous actions too similar to ordinary ones.

Mistake #2: thinking that the URL itself already expresses the access rule.
The route /api/admin/** helps a person read the API, but it does not create protection automatically. It is an address, not an access control. Until the rule is expressed explicitly, the system does not know that “admin” in the path should be taken seriously.

Mistake #3: confusing self-scoped routes and owner-only scenarios.
/api/me and /api/drafts/{id} require different thinking. In the first case, the path is already tightly bound to the current user. In the second, the client selects an object arbitrarily, and that is where the “yours or someone else’s” check quickly appears.

Mistake #4: building the access conversation around roles, not actions.
A role is useful, but it should not overshadow the actual business meaning. First it is useful to state the action: “read a published article,” “update your profile,” “publish a draft submitted for moderation,” “change user roles.” And only then choose the access level for that action.

1
Task
Spring Security, level 1, lesson 0
Locked
Four routes and four access zones
Four routes and four access zones
1
Task
Spring Security, level 1, lesson 0
Locked
Console Access Zone Map
Console Access Zone Map
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION