Menu

HTTP Topic

Authentication and Authorization in HTTP

What You'll Learn:

  • HTTP authentication schemes (Basic, Bearer, Digest)

  • OAuth2 and JWT token-based authentication

  • Implementing security in REST APIs

Authentication and Authorization in HTTP — Detailed Explanation

HTTP is a stateless protocol, meaning it does not remember users from one request to the next.
To protect resources, web apps and APIs need two key mechanisms:


1. Authentication — “Who are you?”

Authentication verifies a user’s identity.

It answers the question:
➡️ “Is this really the person they claim to be?”

Common ways to authenticate in HTTP:


Basic Authentication (Simple but insecure)

Client sends username and password on each request, encoded in Base64.

Header example:

Authorization: Basic dXNlcjpwYXNzd29yZA==

❗ Not secure unless using HTTPS
❗ Password is sent every time


Token-Based Authentication

After logging in, the server gives the client a token.
The client sends this token with each request.

Header:

Authorization: Bearer <token>

Token = proof that the user is authenticated.


JWT (JSON Web Token)

A popular type of token used in REST APIs.

Structure:

header.payload.signature

Contains:

  • User ID

  • Expiration time

  • Permissions

✔ Stateless
✔ No server session storage needed


API Keys (for server-to-server interactions)

Used by systems, not humans.

Header:

x-api-key: 12345abcde

Used when customers call APIs (e.g., OpenAI API keys).


OAuth 2.0 (used by Google, Facebook login)

Allows third-party apps to access your data without sharing your password.

Example:

  • Login with Google

  • App receives an access token

  • App uses token to access user info


2. Authorization — “What can you do?”

Authorization determines what actions or resources an authenticated user is allowed to access.

It answers the question:
“What is this user allowed to do?”

Authorization happens after authentication.


Example Scenario

Step Meaning
Authentication User logs in as “alice”
Authorization Alice is allowed to access /profile, but not /admin

Common Authorization Methods


Role-Based Access Control (RBAC)

Users are assigned roles such as:

  • admin

  • editor

  • viewer

Authorization checks:

if(user.role == "admin") { allow } else { deny }


Permission-Based Access Control

More granular than roles.

Example permissions:

  • CAN_EDIT_POST

  • CAN_DELETE_USER

  • CAN_VIEW_DASHBOARD

Roles can contain multiple permissions.


Attribute-Based Access Control (ABAC)

Decisions based on:

  • User attributes (age, department)

  • Resource attributes (file owner)

  • Environment attributes (time of day)

Example rule:

User can access document if user.department == document.department


How Authentication and Authorization Work Together

Step-by-step request flow:

  1. User logs in
    → Server authenticates credentials

  2. Server issues token
    → JWT, session ID, API key

  3. User sends token with every request

  4. Server checks token validity
    → Authentication

  5. Server checks what user is allowed to do
    → Authorization

  6. Server returns data or denies access


HTTP Headers Used for Auth

Authorization header

Main header for sending credentials/tokens:

Authorization: Bearer <jwt-token>

Set-Cookie header

For session-based authentication:

Set-Cookie: sessionId=abc123; HttpOnly

Custom headers

x-api-key: <your-api-key>

Detailed Explanation:

HTTP Authentication Schemes

1. Basic Authentication:

# Request
GET /api/protected HTTP/1.1
Authorization: Basic dXNlcjpwYXNzd29yZA==

# The token is base64 encoded "username:password"

2. Bearer Token Authentication:

# Request
GET /api/protected HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

# Response for invalid token
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="example", error="invalid_token"

3. Digest Authentication:

# Server challenge
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Digest realm="test", nonce="abc123"

# Client response
Authorization: Digest username="user", realm="test", nonce="abc123",
                uri="/api/protected", response="hashed_response"

OAuth2 Flows

Authorization Code Flow:

1. Client redirects to authorization server
2. User authenticates and grants consent
3. Authorization server returns authorization code
4. Client exchanges code for access token
5. Client uses access token to access resources

Client Credentials Flow (Server-to-Server):

POST /oauth/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&client_id=client123&client_secret=secret456

Response:

json

{
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "read write"
}

JWT (JSON Web Tokens)

JWT Structure:

Header.Payload.Signature

JWT Payload Example:

json

{
  "sub": "1234567890",
  "name": "John Doe",
  "email": "john@example.com",
  "roles": ["USER", "ADMIN"],
  "iat": 1516239022,
  "exp": 1516242622
}

Using JWT in Requests:

GET /api/protected HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Spring Security Implementation

Security Configuration:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable())
            .authorizeHttpRequests(authz -> authz
                .requestMatchers("/api/public/**").permitAll()
                .requestMatchers("/api/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(oauth2 -> oauth2
                .jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter()))
            )
            .sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            );
        
        return http.build();
    }
    
    @Bean
    public JwtDecoder jwtDecoder() {
        return NimbusJwtDecoder.withJwkSetUri("https://idp.example.com/.well-known/jwks.json").build();
    }
    
    private Converter<Jwt, AbstractAuthenticationToken> jwtAuthenticationConverter() {
        JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
        converter.setJwtGrantedAuthoritiesConverter(jwt -> {
            Collection<String> roles = jwt.getClaimAsStringList("roles");
            return roles.stream()
                .map(role -> new SimpleGrantedAuthority("ROLE_" + role))
                .collect(Collectors.toList());
        });
        return converter;
    }
}

JWT Token Service:

@Service
public class JwtTokenService {
    
    private final JwtEncoder jwtEncoder;
    private final JwtDecoder jwtDecoder;
    
    public String generateToken(User user) {
        Instant now = Instant.now();
        
        JwtClaimsSet claims = JwtClaimsSet.builder()
            .issuer("my-app")
            .issuedAt(now)
            .expiresAt(now.plus(1, ChronoUnit.HOURS))
            .subject(user.getId().toString())
            .claim("name", user.getName())
            .claim("email", user.getEmail())
            .claim("roles", user.getRoles())
            .build();
        
        return jwtEncoder.encode(JwtEncoderParameters.from(claims)).getTokenValue();
    }
    
    public boolean validateToken(String token) {
        try {
            Jwt jwt = jwtDecoder.decode(token);
            return jwt.getExpiresAt().isAfter(Instant.now());
        } catch (Exception e) {
            return false;
        }
    }
}

API Key Authentication

Custom API Key Filter:

@Component
public class ApiKeyAuthFilter extends OncePerRequestFilter {
    
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                  HttpServletResponse response,
                                  FilterChain chain) throws IOException, ServletException {
        
        String apiKey = getApiKeyFromRequest(request);
        
        if (apiKey != null) {
            Authentication auth = authenticateWithApiKey(apiKey);
            SecurityContextHolder.getContext().setAuthentication(auth);
        }
        
        chain.doFilter(request, response);
    }
    
    private String getApiKeyFromRequest(HttpServletRequest request) {
        String header = request.getHeader("X-API-Key");
        if (header != null) {
            return header;
        }
        
        String param = request.getParameter("api_key");
        if (param != null) {
            return param;
        }
        
        return null;
    }
    
    private Authentication authenticateWithApiKey(String apiKey) {
        User user = userService.findByApiKey(apiKey);
        if (user == null) {
            throw new BadCredentialsException("Invalid API key");
        }
        
        return new ApiKeyAuthenticationToken(user, apiKey, user.getAuthorities());
    }
}

Rate Limiting with Authentication

Rate Limit Filter:

@Component
public class RateLimitFilter extends OncePerRequestFilter {
    
    private final RateLimiter rateLimiter;
    
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                  HttpServletResponse response,
                                  FilterChain chain) throws IOException, ServletException {
        
        String clientId = getClientIdentifier(request);
        
        if (!rateLimiter.tryAcquire(clientId)) {
            response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
            response.getWriter().write("Rate limit exceeded");
            return;
        }
        
        chain.doFilter(request, response);
    }
    
    private String getClientIdentifier(HttpServletRequest request) {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null && auth.isAuthenticated()) {
            return auth.getName(); // User ID or username
        }
        
        return request.getRemoteAddr(); // IP address as fallback
    }
}

Security Headers for APIs

Secure Response Headers:

@Component
public class SecurityHeadersFilter implements Filter {
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                        FilterChain chain) throws IOException, ServletException {
        
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        
        // Prevent MIME sniffing
        httpResponse.setHeader("X-Content-Type-Options", "nosniff");
        
        // Prevent clickjacking
        httpResponse.setHeader("X-Frame-Options", "DENY");
        
        // Enable HSTS
        httpResponse.setHeader("Strict-Transport-Security", 
                              "max-age=31536000; includeSubDomains");
        
        // Content Security Policy
        httpResponse.setHeader("Content-Security-Policy", 
                              "default-src 'self'; script-src 'self'");
        
        chain.doFilter(request, response);
    }
}

 

Comments (0)

No comments yet. Be the first to comment!

LecturreAI Assistant

Hello! I'm LecturreAI

What would you like to learn today?