Back to Authentication & Authorization
Q2Question 2 of 4

Authentication vs Authorization (who are you vs what can you do)

Key Concepts
  • Authentication verifies identity: proving the caller is who they claim to be using credentials, tokens, or certificates.
  • Authorization decides permissions: determining whether an authenticated principal may perform a specific action on a specific resource.
  • Authentication always runs first; authorization depends on its result and cannot happen without it.
  • A failed authentication returns HTTP 401 Unauthorized; a failed authorization returns HTTP 403 Forbidden.
  • Spring Security separates the two with AuthenticationManager for identity and AccessDecisionManager for permissions.
  • In banking, mixing identity and permission logic leads to bugs where a valid login accidentally grants access to the wrong account.

Definition

Authentication proves WHO you are; authorization decides WHAT you may do.
  • Authentication – the process of verifying the identity of a principal, proving that a user, service, or device really is who it claims to be, usually through credentials such as a password, a JWT, or a client certificate.
  • Authorization – the process of deciding whether an already-authenticated principal is permitted to perform a specific action on a specific resource, usually driven by roles, permissions, or policies.
  • Order – authentication always happens first; authorization runs after and depends on its result.
  • HTTP signals – authentication failure returns 401 Unauthorized; authorization failure returns 403 Forbidden.
  • Spring Security – authentication is handled by AuthenticationManager and filters; authorization is handled by AccessDecisionManager, URL rules, and method annotations like @PreAuthorize.

When Rajesh walks into National Bank of India, he shows his ID card at the entrance and the guard checks the photo to confirm he is Rajesh. That is authentication. But proving he is Rajesh does not let him walk into the vault. When Rajesh asks to withdraw from account SAV2001, the teller checks whether this account belongs to him and whether he is allowed to take out this much. That is authorization. Priya can be perfectly authenticated as Priya and still be refused when she tries to touch Rajesh's account.

Understanding the Concepts

What is authentication?

Authentication answers the identity question: who are you? The caller presents a credential, and the system verifies it against a trusted store. If the credential is valid, the system creates an identity context that downstream code can rely on.

In Spring Security, the result of authentication is an Authentication object placed into the SecurityContext. After a successful login, SecurityContextHolder.getContext().getAuthentication().getName() returns the username, and isAuthenticated() returns true.

Common authentication mechanisms include username and password (form login), bearer tokens like JWT in the Authorization header, API keys, and mutual TLS client certificates.

JAVA
package com.bank.security;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

public class AuthenticationDemo {

    public static void printCurrentUser() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        System.out.println("User: " + auth.getName());
        System.out.println("Authenticated: " + auth.isAuthenticated());
        System.out.println("Authorities: " + auth.getAuthorities());
    }
}
TEXT
User: rajesh
Authenticated: true
Authorities: [ROLE_CUSTOMER]

What is authorization?

Authorization answers the permission question: what can you do? It runs only after authentication succeeds and uses the authenticated identity to evaluate access rules.

In Spring Security you express authorization with method-level annotations or URL rules. For example, @PreAuthorize("hasRole('ADMIN')") on a service method restricts it to admins, while .requestMatchers("/api/v1/admin/**").hasRole("ADMIN") restricts a URL path.

JAVA
package com.bank.service;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;

@Service
public class AccountService {

    @PreAuthorize("#accountId == authentication.name or hasRole('TELLER')")
    public BigDecimal getBalance(String accountId) {
        // A customer can see only their own account.
        // A teller can see any account.
        return new BigDecimal("125000.75");
    }

    @PreAuthorize("hasRole('ADMIN')")
    public void closeAccount(String accountId) {
        System.out.println("Account " + accountId + " closed by admin.");
    }
}
TEXT
// Rajesh (CUSTOMER) calls getBalance("rajesh") --> allowed (own account)
// Rajesh (CUSTOMER) calls getBalance("priya")  --> 403 Forbidden
// Priya  (TELLER)   calls getBalance("rajesh") --> allowed (teller role)
// Rajesh (CUSTOMER) calls closeAccount("rajesh") --> 403 Forbidden

How is authentication different from authorization?

| Aspect | Authentication | Authorization |
|---|---|---|
| Question | Who are you? | What can you do? |
| When | Runs first | Runs after authentication |
| Input | Credentials (password, token, certificate) | Identity + requested action + resource |
| Output | Identity context (Authentication object) | Allow or deny decision |
| HTTP failure code | 401 Unauthorized | 403 Forbidden |
| Spring Security | AuthenticationManager, filters | AccessDecisionManager, @PreAuthorize |
| Nature | Binary (you are or are not that principal) | Contextual (same user may read but not delete) |

JAVA
package com.bank.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                // Authentication: anyone can reach the login page
                .requestMatchers("/login", "/public/**").permitAll()
                // Authorization: only ADMIN can reach admin endpoints
                .requestMatchers("/api/v1/admin/**").hasRole("ADMIN")
                // Authorization: only TELLER or ADMIN can approve transfers
                .requestMatchers("/api/v1/transfers/approve").hasAnyRole("TELLER", "ADMIN")
                // Everything else needs authentication
                .anyRequest().authenticated()
            )
            .formLogin(form -> form.loginPage("/login"));
        return http.build();
    }
}

Why does the order matter?

Authentication must happen before authorization because the system cannot decide permissions for an unknown caller. If you skip authentication and go straight to authorization, you have no identity to evaluate rules against.

In Spring Security the filter chain enforces this order automatically. The UsernamePasswordAuthenticationFilter or BearerTokenAuthenticationFilter runs first and populates the SecurityContext. Only then do the authorization filters and @PreAuthorize annotations evaluate.

JAVA
package com.bank.controller;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TransferController {

    @GetMapping("/api/v1/transfers")
    public ResponseEntity<String> listTransfers() {
        // If no valid token/session --> 401 (authentication failed)
        // If valid token but role is CUSTOMER, not TELLER --> 403 (authorization failed)
        return ResponseEntity.ok("Transfer list for authorized teller.");
    }
}
TEXT
curl -X GET /api/v1/transfers
--> 401 Unauthorized (no credentials provided)

curl -X GET /api/v1/transfers -H "Authorization: Bearer <rajesh_customer_token>"
--> 403 Forbidden (authenticated but not a teller)

curl -X GET /api/v1/transfers -H "Authorization: Bearer <priya_teller_token>"
--> 200 OK (authenticated and authorized)

What are common mistakes?

The most common mistake is confusing the HTTP status codes. A 401 means the server does not know who the caller is. A 403 means the server knows who the caller is but the caller lacks permission.

Another common mistake is mixing authentication and authorization logic in the same method, which leads to bugs where a valid login accidentally grants access to the wrong resource.

JAVA
package com.bank.service;

// WRONG: mixed authentication and authorization logic
public class WrongTransferService {

    public void transfer(String username, String password, String fromAccount, String toAccount) {
        if (username.equals("rajesh") && password.equals("pass123")) {
            // Bug: anyone who logs in as rajesh can transfer from ANY account
            executeTransfer(fromAccount, toAccount);
        }
    }

    private void executeTransfer(String from, String to) { }
}

// CORRECT: separate authentication from authorization
public class CorrectTransferService {

    // Authentication handled by Spring Security filter chain
    // Authorization enforced by @PreAuthorize
    @PreAuthorize("#fromAccount == authentication.name or hasRole('TELLER')")
    public void transfer(String fromAccount, String toAccount) {
        executeTransfer(fromAccount, toAccount);
    }

    private void executeTransfer(String from, String to) { }
}

How does Spring Security implement both?

Spring Security separates the two concerns cleanly. Authentication is handled by AuthenticationManager, which delegates to AuthenticationProvider implementations. The most common provider is DaoAuthenticationProvider, which loads user details from a UserDetailsService and checks the password with a PasswordEncoder.

Authorization is handled separately through AuthorizationManager (or the older AccessDecisionManager), URL-based rules in SecurityFilterChain, and method-level annotations processed by MethodSecurityInterceptor.

JAVA
package com.bank.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@Configuration
public class AuthConfig {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(12);
    }

    @Bean
    public UserDetailsService userDetailsService(PasswordEncoder encoder) {
        var rajesh = User.builder()
            .username("rajesh")
            .password(encoder.encode("securePass2024"))
            .roles("CUSTOMER")
            .build();
        var priya = User.builder()
            .username("priya")
            .password(encoder.encode("tellerPass2024"))
            .roles("TELLER")
            .build();
        return new InMemoryUserDetailsManager(rajesh, priya);
    }
}

What about 401 vs 403 in practice?

The distinction matters for client-side handling. A 401 tells the client to show a login screen. A 403 tells the client that the user is logged in but lacks permission, so showing a login screen would be wrong.

JAVA
package com.bank.security;

import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ErrorHandlerConfig {

    @Bean
    public AuthenticationEntryPoint authEntryPoint() {
        return (request, response, authException) -> {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 401
            response.getWriter().write("{\"error\":\"Please log in to access this resource.\"}");
        };
    }

    @Bean
    public AccessDeniedHandler accessDeniedHandler() {
        return (request, response, accessDeniedException) -> {
            response.setStatus(HttpServletResponse.SC_FORBIDDEN); // 403
            response.getWriter().write("{\"error\":\"You do not have permission for this action.\"}");
        };
    }
}

What should a senior engineer know?

A senior engineer should understand that authentication is binary while authorization is contextual. The same user may be allowed to read an account but not delete it. The same teller may approve transfers under 50,000 rupees but not above that limit.

Senior engineers also know that separating the two concerns makes the system auditable. You can log every 401 and every 403 separately and prove exactly where and why access was refused, which is a regulatory requirement in banking.

Another senior-level concern is the difference between identity propagation and permission propagation in microservices. The authentication token travels with the request, but each service makes its own authorization decision based on its own rules.

What are common interview follow-up questions?

  • What HTTP status code does a failed login return? (401 Unauthorized)
  • What HTTP status code does an unauthorized action return? (403 Forbidden)
  • Can authorization happen without authentication? (No, you need an identity first.)
  • How does Spring Security separate the two? (AuthenticationManager for identity, authorization rules and @PreAuthorize for permissions.)
  • What is the difference between hasRole and hasAuthority in Spring Security? (hasRole adds the ROLE_ prefix automatically; hasAuthority checks the exact string.)

Visual Overview

DIAGRAM
  Client Request
       │
       ▼
  ┌─────────────────────────────────────┐
  │        AUTHENTICATION LAYER          │
  │  "Who are you?"                      │
  │                                      │
  │  Credentials ──► AuthenticationMgr   │
  │                      │               │
  │              ┌───────┴───────┐       │
  │              │               │       │
  │           Success          Fail      │
  │           (Identity)     (401)       │
  └──────────────┬──────────────────────┘
                 │
                 ▼
  ┌─────────────────────────────────────┐
  │        AUTHORIZATION LAYER           │
  │  "What can you do?"                  │
  │                                      │
  │  Identity + Action ──► AccessMgr     │
  │                           │          │
  │                 ┌─────────┴──────┐   │
  │                 │                │   │
  │              Allowed          Denied │
  │              (200 OK)        (403)  │
  └─────────────────────────────────────┘
DIAGRAM
  Rajesh (CUSTOMER)           Priya (TELLER)
       │                           │
       ▼                           ▼
  Auth: ✓ rajesh              Auth: ✓ priya
       │                           │
       ▼                           ▼
  GET /accounts/rajesh        GET /accounts/rajesh
  Authz: ✓ (own account)     Authz: ✓ (teller role)
       │                           │
       ▼                           ▼
  GET /accounts/priya         POST /transfers/approve
  Authz: ✗ 403 (not owner)   Authz: ✓ (teller role)

Key Takeaway

Authentication is the process of verifying identity: proving that the caller really is who they claim to be, typically by checking a password, a JWT signature, or a client certificate. Authorization is the process of deciding whether that already-known identity is permitted to perform a particular action on a particular resource. The order matters: authentication always runs first, and authorization depends on its result.

In the National Bank of India project, these two concerns live in separate layers. The authentication layer validates the user's credentials and, on success, places an identity object into the security context. Only after that does the authorization layer run, checking rules like a customer may only touch accounts they own, while a teller may touch any account. So when Rajesh logs in successfully but tries to open Priya's account, authentication passes but authorization fails with a 403.

A detail that interviewers test is the status codes: an authentication failure returns 401 Unauthorized, meaning the server does not know who the caller is, while an authorization failure returns 403 Forbidden, meaning the server knows the caller but the caller lacks permission. In Spring Security, authentication is handled by filters and an AuthenticationManager, and authorization is handled by URL rules and method-level annotations such as @PreAuthorize.

The reason this separation matters in banking is blast radius: mixing identity and permission logic leads to bugs where a valid login accidentally grants access to the wrong account. Keeping them distinct makes the system auditable. You can log every 401 and every 403 separately and prove exactly where and why access was refused.

Remember one sentence: authentication proves who you are, authorization decides what you may do, and they must always be separate concerns.

---

Share
Use ← → arrow keys to navigate