DEV Community

khg5293
khg5293

Posted on

Why Authentication and Authorization Are Not the Same Thing

Authentication and authorization are often mentioned together, so it is easy to treat them as if they are the same thing.

They are not.

A simple way to think about it is:

  • Authentication answers: Who are you?
  • Authorization answers: What are you allowed to do?

A user can be successfully authenticated and still be unauthorized to access a resource.

That distinction matters because many security bugs happen when an application verifies identity but fails to verify permissions.

Authentication: Proving Identity

Authentication is the process of verifying that a user is who they claim to be.

A common example is logging into a website with a username and password.

Username: khg5293
Password: ********
Enter fullscreen mode Exit fullscreen mode

If the credentials are valid, the server may create a session and return a session cookie.

Set-Cookie: sessionId=abc123xyz;
Enter fullscreen mode Exit fullscreen mode

From that point on, the browser can send the cookie with later requests.

GET /account
Cookie: sessionId=abc123xyz
Enter fullscreen mode Exit fullscreen mode

The server checks the session and determines:

This request belongs to khg5293.
Enter fullscreen mode Exit fullscreen mode

That is authentication.

The server now knows who is making the request.

But that does not automatically mean the user should be allowed to access everything.

Authorization: Checking Permissions

Authorization happens after identity is known.

Imagine the application has two users:

khg5293
admin
Enter fullscreen mode Exit fullscreen mode

Both users can authenticate successfully.

But they should not necessarily have the same permissions.

For example:

GET /admin/dashboard
Enter fullscreen mode Exit fullscreen mode

The server should not only ask:

Is this user logged in?
Enter fullscreen mode Exit fullscreen mode

It also needs to ask:

Is this user allowed to access the admin dashboard?
Enter fullscreen mode Exit fullscreen mode

A simplified example might look like this:

function viewAdminDashboard(user) {
  if (!user.isAuthenticated) {
    return "Please log in";
  }

  if (user.role !== "admin") {
    return "Access denied";
  }

  return "Welcome to the admin dashboard";
}
Enter fullscreen mode Exit fullscreen mode

The first check is authentication.

if (!user.isAuthenticated)
Enter fullscreen mode Exit fullscreen mode

The second check is authorization.

if (user.role !== "admin")
Enter fullscreen mode Exit fullscreen mode

They solve different problems.

Being Logged In Is Not Enough

One of the most common mistakes is assuming that authentication automatically provides authorization.

Consider this request:

GET /users/khg5293/profile
Enter fullscreen mode Exit fullscreen mode

The server might read the authenticated user from the session.

const sessionUser = "khg5293";
Enter fullscreen mode Exit fullscreen mode

Now imagine the user changes the request manually:

GET /users/admin/profile
Enter fullscreen mode Exit fullscreen mode

If the server only checks whether the requester is logged in, the request might succeed.

if (sessionUser) {
  return getProfile(request.params.username);
}
Enter fullscreen mode Exit fullscreen mode

That code confirms that the requester is authenticated.

But it never checks whether the authenticated user is authorized to view the requested profile.

A safer approach would be:

const sessionUser = "khg5293";
const requestedUser = request.params.username;

if (!sessionUser) {
  return "Authentication required";
}

if (sessionUser !== requestedUser) {
  return "Access denied";
}

return getProfile(requestedUser);
Enter fullscreen mode Exit fullscreen mode

Now the server verifies both identity and permission.

Authentication Usually Comes First

In many applications, the flow looks like this:

1. User sends credentials
2. Server verifies credentials
3. Server creates a session
4. User sends a request
5. Server identifies the user from the session
6. Server checks whether that user is allowed to perform the requested action
Enter fullscreen mode Exit fullscreen mode

Steps 1 through 5 involve authentication.

Step 6 is authorization.

They are related, but they are separate security decisions.

Authorization Should Be Checked on the Server

Authorization checks should not rely only on the user interface.

For example, a frontend application might hide an admin button:

if (user.role === "admin") {
  showAdminButton();
}
Enter fullscreen mode Exit fullscreen mode

That is useful for the interface.

But hiding a button does not protect the server endpoint.

An attacker can skip the browser interface completely and send requests directly.

DELETE /api/users/123
Enter fullscreen mode Exit fullscreen mode

If the backend does not perform its own authorization check, hiding the button provides no real protection.

The server still needs something like:

app.delete("/api/users/:id", (req, res) => {
  const user = req.session.user;

  if (!user) {
    return res.status(401).send("Authentication required");
  }

  if (user.role !== "admin") {
    return res.status(403).send("Forbidden");
  }

  deleteUser(req.params.id);

  res.send("User deleted");
});
Enter fullscreen mode Exit fullscreen mode

The frontend can improve usability.

The backend must enforce security.

401 and 403 Are Different for the Same Reason

HTTP status codes also reflect the difference between authentication and authorization.

A 401 Unauthorized response usually means:

You have not successfully authenticated.
Enter fullscreen mode Exit fullscreen mode

For example:

HTTP/1.1 401 Unauthorized
Enter fullscreen mode Exit fullscreen mode

A 403 Forbidden response usually means:

The server knows who you are, but you are not allowed to perform this action.
Enter fullscreen mode Exit fullscreen mode

For example:

HTTP/1.1 403 Forbidden
Enter fullscreen mode Exit fullscreen mode

Despite the slightly confusing name of the 401 Unauthorized status code, the practical distinction is useful:

401 -> Who are you?
403 -> You are not allowed to do that.
Enter fullscreen mode Exit fullscreen mode

A Simple Example

Suppose khg5293 logs into an application.

The server authenticates the user:

const user = {
  username: "khg5293",
  role: "user",
  isAuthenticated: true
};
Enter fullscreen mode Exit fullscreen mode

Now the user tries to open a normal account page.

GET /account
Enter fullscreen mode Exit fullscreen mode

The server allows it.

if (user.isAuthenticated) {
  return showAccountPage();
}
Enter fullscreen mode Exit fullscreen mode

Then the same user tries to access an administrative endpoint.

GET /admin/users
Enter fullscreen mode Exit fullscreen mode

The server checks authorization.

if (user.role !== "admin") {
  return "Access denied";
}
Enter fullscreen mode Exit fullscreen mode

The user is still authenticated.

The authentication did not fail.

The authorization check failed.

That is the key distinction.

Why the Difference Matters

Security problems can appear when developers combine these concepts into a single question:

Is the user logged in?
Enter fullscreen mode Exit fullscreen mode

That question is often not enough.

Applications may also need to ask:

Who owns this resource?
What role does this user have?
Can this user perform this specific action?
Does this user belong to this organization?
Is this resource accessible to this account?
Enter fullscreen mode Exit fullscreen mode

Those are authorization questions.

A secure application should treat them separately from authentication.

Final Thought

Authentication establishes identity.

Authorization establishes permission.

Authentication:
"Who are you?"

Authorization:
"What are you allowed to do?"
Enter fullscreen mode Exit fullscreen mode

A user can pass authentication successfully and still fail authorization.

Keeping those concepts separate makes application security easier to reason about and helps prevent situations where a valid user gains access to something they were never supposed to reach.

Top comments (0)