Skip to main content

Is It Safe to Send Passwords in Login Requests? HTTP vs HTTPS Security

ยท 14 min read
Mahmut Salman
Software Developer

"Is it safe to add password in LoginRequest? Can someone reach the user's request?" Great security question! The answer depends entirely on whether you're using HTTP or HTTPS. With HTTP, anyone on the network can see your password in plain text. With HTTPS, it's encrypted end-to-end. Let's understand the difference and how to secure your login.

The Login Requestโ€‹

@PostMapping("/auth/login")
public ResponseEntity<LoginResponse> login(@RequestBody LoginRequest request) {
// request.getPassword() contains plain text password
User user = userRepository.findByEmail(request.getEmail())
.orElseThrow(() -> new RuntimeException("Invalid credentials"));

if (passwordEncoder.matches(request.getPassword(), user.getPassword())) {
return ResponseEntity.ok(new LoginResponse(user.getId(), ...));
}
throw new RuntimeException("Invalid credentials");
}

Request body (JSON):

{
"email": "testuser@example.com",
"password": "testpass123"
}

The question: Can someone intercept this password during transmission?


The Risk: HTTP vs HTTPSโ€‹

โŒ HTTP (UNSAFE)โ€‹

Client                Network               Server
โ”‚ โ”‚ โ”‚
โ”‚ {"password": "..."} โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ†’ โ”‚
โ”‚ (PLAIN TEXT!) โ”‚

What happens:

  1. Client sends JSON with password
  2. Password travels through network unencrypted
  3. Anyone on the network can see it

Who can intercept:

  • โ˜ ๏ธ Your ISP (Internet Service Provider)
  • โ˜ ๏ธ WiFi network owner (coffee shop, airport)
  • โ˜ ๏ธ Anyone on the same WiFi network
  • โ˜ ๏ธ Man-in-the-middle attackers
  • โ˜ ๏ธ Network administrators
  • โ˜ ๏ธ Hackers using packet sniffers

โœ… HTTPS (SAFE)โ€‹

Client                Network               Server
โ”‚ โ”‚ โ”‚
โ”‚ {"password": "..."} โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ†’ โ”‚
โ”‚ (ENCRYPTED!) โ”‚
โ”‚ [garbled encrypted data] โ”‚

What happens:

  1. Client sends JSON with password
  2. Password is encrypted before leaving your device
  3. Travels through network as encrypted gibberish
  4. Only the server can decrypt it

Who can see:

  • โœ… Only your client and the server
  • โŒ Network observers see encrypted data (useless without decryption key)

HTTP: How the Attack Worksโ€‹

The Scenarioโ€‹

You're at a coffee shop using their WiFi:

Your Laptop  โ†’  Coffee Shop WiFi  โ†’  Internet  โ†’  Server
โ†‘
Hacker
(using Wireshark)

What the Hacker Sees (HTTP)โ€‹

Network packet captured:

POST /api/auth/login HTTP/1.1
Host: yourapp.com
Content-Type: application/json
Content-Length: 67

{
"email": "testuser@example.com",
"password": "testpass123"
}

Hacker now has:

  • โœ… Your email: testuser@example.com
  • โœ… Your password: testpass123
  • โœ… The API endpoint: /api/auth/login

Game over! ๐Ÿšจ

What the Hacker Sees (HTTPS)โ€‹

Network packet captured:

POST /api/auth/login HTTP/1.1
Host: yourapp.com
Content-Type: application/json
Content-Length: 67

๏ฟฝ๏ฟฝ๏ฟฝXs๏ฟฝ9k๏ฟฝ2๏ฟฝM๏ฟฝ๏ฟฝ๏ฟฝvT๏ฟฝ8o๏ฟฝ๏ฟฝP๏ฟฝ๏ฟฝ๏ฟฝ1๏ฟฝG๏ฟฝ๏ฟฝk
ลซ๏ฟฝX๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝาซ๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝG๏ฟฝ๏ฟฝฯ›๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝฯญr๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ๏ฟฝ

Hacker sees:

  • โŒ Encrypted gibberish
  • โŒ Cannot decrypt without private key
  • โŒ Useless data

You're safe! โœ…


HTTPS Encryption Explainedโ€‹

How HTTPS Worksโ€‹

1. Client โ†’ Server: "Hello, I want HTTPS"
2. Server โ†’ Client: "Here's my SSL certificate and public key"
3. Client: Verifies certificate is legitimate
4. Client: Generates session key, encrypts it with server's public key
5. Client โ†’ Server: Sends encrypted session key
6. Server: Decrypts session key with private key
7. Both use session key for symmetric encryption
8. All data encrypted/decrypted using session key

Result: End-to-end encryption of all data including passwords.

Visual Flowโ€‹

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Client (Your Browser/Postman) โ”‚
โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚ โ”‚ LoginRequest โ”‚ โ”‚
โ”‚ โ”‚ { "email": "user@example.com", "password": "pass123" } โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ†“
[TLS/SSL Encryption Layer]
โ†“
Encrypted: ๏ฟฝ๏ฟฝk๏ฟฝ๏ฟฝvT๏ฟฝ8o๏ฟฝ๏ฟฝP๏ฟฝ๏ฟฝ๏ฟฝ1๏ฟฝG
โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Network (WiFi, Internet, ISP) โ”‚
โ”‚ โš ๏ธ Anyone can see traffic here โ”‚
โ”‚ BUT: sees only encrypted gibberish โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ†“
[TLS/SSL Decryption Layer]
โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Server (Spring Boot) โ”‚
โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚ โ”‚ LoginRequest (decrypted) โ”‚ โ”‚
โ”‚ โ”‚ { "email": "user@example.com", "password": "pass123" } โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Critical Misunderstanding: "Wait - We're Hashing the Password!"โ€‹

The Confusionโ€‹

You might think:

"But we're using passwordEncoder.encode(request.getPassword()) to hash the password, so it's secure, right?"

Wrong! Let's understand exactly when hashing happens:

The Complete Registration/Login Flowโ€‹

Registration:

@PostMapping("/auth/register")
public ResponseEntity<UserResponse> register(@RequestBody RegisterRequest request) {
User user = new User();
user.setEmail(request.getEmail());
user.setPassword(passwordEncoder.encode(request.getPassword())); // โ† Hashing happens HERE
userRepository.save(user);
return ResponseEntity.ok(new UserResponse(...));
}

Step-by-step breakdown:

1. Client (Postman) sends HTTP POST:
POST http://localhost:8082/api/auth/register
Body: {"email": "test@example.com", "password": "testpass123"}
โ†“
โš ๏ธ PASSWORD IN PLAIN TEXT IN TRANSIT!

2. Request travels through network:
Network sees: {"email": "test@example.com", "password": "testpass123"}
โ†“
โŒ ANYONE CAN INTERCEPT THIS!

3. Server receives request:
request.getPassword() = "testpass123" (still plain text)
โ†“

4. Server hashes password:
passwordEncoder.encode("testpass123")
โ†’ "$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy"
โ†“

5. Server stores hash in database:
Database: password = "$2a$10$N9qo8..."
โœ… SAFE IN DATABASE

6. Server sends response:
{"id": 4, "username": "testuser", "email": "testuser@example.com", ...}
โ†“
โœ… NO PASSWORD IN RESPONSE (safe)

The Problem: Hashing Happens on the SERVER, Not in Transitโ€‹

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ TRANSMISSION (Network) โ”‚
โ”‚ โ”‚
โ”‚ Client โ”€โ”€โ”€โ”€โ”€โ”€โ†’ Network โ”€โ”€โ”€โ”€โ”€โ”€โ†’ Server โ”‚
โ”‚ (PLAIN TEXT!) โ”‚
โ”‚ โ”‚
โ”‚ โŒ Hashing doesn't protect this part! โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ STORAGE (Database) โ”‚
โ”‚ โ”‚
โ”‚ Server โ†’ Database โ”‚
โ”‚ (HASHED: $2a$10$...) โ”‚
โ”‚ โ”‚
โ”‚ โœ… Hashing protects this part! โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

What Each Security Measure Protectsโ€‹

Security MeasureWhat It ProtectsWhat It DOESN'T Protect
Password HashingDatabase storageNetwork transmission
HTTPS EncryptionNetwork transmissionDatabase storage
Both TogetherComplete securityโœ… Everything protected

Visual Comparisonโ€‹

HTTP + Hashing (INCOMPLETE SECURITY):

Client                        Network                    Server                Database
โ”‚ โ”‚ โ”‚ โ”‚
โ”‚ {"password": "testpass123"} โ”‚ โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ†’ โ”‚ โ”‚
โ”‚ โŒ PLAIN TEXT โ”‚ โ”‚
โ”‚ โ”‚ โ”‚ โ”‚
โ”‚ โ†‘ โ”‚ โ”‚
โ”‚ [Hacker intercepts] โ”‚ โ”‚
โ”‚ โœ“ Sees: "testpass123" โ”‚ โ”‚
โ”‚ โ”‚ โ”‚ โ”‚
โ”‚ โ”‚ passwordEncoder.encode(...) โ”‚
โ”‚ โ”‚ โ”‚ โ”‚
โ”‚ โ”‚ โ”‚ "$2a$10$N9qo..." โ”‚
โ”‚ โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ†’โ”‚
โ”‚ โ”‚ โ”‚ โœ… HASHED โ”‚

Result: Hacker intercepts plain password before it reaches server! ๐Ÿšจ

HTTPS + Hashing (COMPLETE SECURITY):

Client                        Network                    Server                Database
โ”‚ โ”‚ โ”‚ โ”‚
โ”‚ {"password": "testpass123"} โ”‚ โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ†’ [TLS Encryption] โ”‚ โ”‚
โ”‚ โ”‚ โ”‚ โ”‚
โ”‚ Encrypted: ๏ฟฝ๏ฟฝk๏ฟฝ๏ฟฝvT๏ฟฝ8o๏ฟฝ๏ฟฝP๏ฟฝ๏ฟฝ๏ฟฝ1๏ฟฝG โ”‚ โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ†’ โ”‚ โ”‚
โ”‚ โœ… ENCRYPTED โ”‚ โ”‚
โ”‚ โ”‚ โ”‚ โ”‚
โ”‚ โ†‘ โ”‚ โ”‚
โ”‚ [Hacker intercepts] โ”‚ โ”‚
โ”‚ โœ— Sees: "๏ฟฝ๏ฟฝk๏ฟฝ๏ฟฝvT๏ฟฝ8o๏ฟฝ๏ฟฝ" โ”‚ โ”‚
โ”‚ โœ— Cannot decrypt! โ”‚ โ”‚
โ”‚ โ”‚ โ”‚ โ”‚
โ”‚ โ”‚ [TLS Decryption] โ”‚ โ”‚
โ”‚ โ”‚ "testpass123" โ”‚ โ”‚
โ”‚ โ”‚ โ”‚ โ”‚
โ”‚ โ”‚ passwordEncoder.encode(...) โ”‚
โ”‚ โ”‚ โ”‚ โ”‚
โ”‚ โ”‚ โ”‚ "$2a$10$N9qo..." โ”‚
โ”‚ โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ†’โ”‚
โ”‚ โ”‚ โ”‚ โœ… HASHED โ”‚

Result: Hacker sees only encrypted gibberish! โœ…

The Response is Safe (No Password)โ€‹

{
"id": 4,
"username": "testuser",
"email": "testuser@example.com",
"role": "USER",
"message": "Login successful"
}

This response is safe because:

  • โœ… No password included
  • โœ… Only public data (username, email, role)
  • โœ… Even over HTTP, this response doesn't expose credentials

But the REQUEST was the problem!

Summary Tableโ€‹

ScenarioRequest SecurityDatabase SecurityOverall
HTTP + No HashingโŒ Plain text in transitโŒ Plain text in DBโŒโŒ Completely insecure
HTTP + HashingโŒ Plain text in transitโœ… Hashed in DBโŒ Still vulnerable
HTTPS + No Hashingโœ… Encrypted in transitโŒ Plain text in DBโŒ Still vulnerable
HTTPS + Hashingโœ… Encrypted in transitโœ… Hashed in DBโœ…โœ… Completely secure

You MUST use BOTH HTTPS and password hashing for complete security!


What Actually Happens When You Enable HTTPS?โ€‹

The "Magic" Explainedโ€‹

When you configure HTTPS in Spring Boot, several components work together to encrypt your traffic automatically. Let's demystify the magic:

HTTPS = HTTP + TLS/SSLโ€‹

HTTP (plain communication)
+
TLS/SSL (encryption protocol)
=
HTTPS (secure communication)

The Components Involvedโ€‹

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Your Spring Boot Application โ”‚
โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚ โ”‚ @RestController โ”‚ โ”‚
โ”‚ โ”‚ @PostMapping("/auth/login") โ”‚ โ”‚
โ”‚ โ”‚ public ResponseEntity<LoginResponse> login(...) โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚ โ†“ โ”‚
โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚ โ”‚ Spring Boot (port 8443) โ”‚ โ”‚
โ”‚ โ”‚ - Reads application.properties โ”‚ โ”‚
โ”‚ โ”‚ - Configures SSL/TLS โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚ โ†“ โ”‚
โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚ โ”‚ Embedded Tomcat Web Server โ”‚ โ”‚
โ”‚ โ”‚ - Listens on HTTPS port โ”‚ โ”‚
โ”‚ โ”‚ - Handles SSL/TLS handshake โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚ โ†“ โ”‚
โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚ โ”‚ TLS/SSL Protocol Layer โ”‚ โ”‚
โ”‚ โ”‚ - Encrypts outgoing data โ”‚ โ”‚
โ”‚ โ”‚ - Decrypts incoming data โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚ โ†“ โ”‚
โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚ โ”‚ SSL Certificate + Private Key (keystore.p12) โ”‚ โ”‚
โ”‚ โ”‚ - Public key: shared with clients โ”‚ โ”‚
โ”‚ โ”‚ - Private key: kept secret โ”‚ โ”‚
โ”‚ โ”‚ - Certificate: proof of identity โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ†“
Network

The TLS Handshake (The "Magic" โœจ)โ€‹

When a client connects to https://localhost:8443, this happens automatically in ~100ms:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Step 1: Client Hello โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Client โ†’ Server: โ”‚
โ”‚ "Hello! I want to establish a secure connection" โ”‚
โ”‚ "I support these encryption algorithms: [AES-256, ...]" โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Step 2: Server Hello + Certificate โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Server โ†’ Client: โ”‚
โ”‚ "Hello! Here's my SSL certificate" โ”‚
โ”‚ "Here's my public key: [public key data]" โ”‚
โ”‚ "Let's use AES-256 encryption" โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Step 3: Client Verifies Certificate โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Client checks: โ”‚
โ”‚ โœ“ Is certificate valid? โ”‚
โ”‚ โœ“ Is it issued by trusted authority? โ”‚
โ”‚ โœ“ Does domain match? โ”‚
โ”‚ โœ“ Is it expired? โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Step 4: Client Generates Session Key โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Client: โ”‚
โ”‚ "I'll generate a random secret key" โ”‚
โ”‚ session_key = random_bytes(256) โ”‚
โ”‚ "Now I'll encrypt it with server's public key" โ”‚
โ”‚ encrypted_key = encrypt(session_key, server_public_key) โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Step 5: Client Sends Encrypted Session Key โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Client โ†’ Server: โ”‚
โ”‚ "Here's the session key (encrypted): [encrypted_key]" โ”‚
โ”‚ โ”‚
โ”‚ โš ๏ธ Even if intercepted, only server can decrypt it! โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Step 6: Server Decrypts Session Key โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Server: โ”‚
โ”‚ "I'll decrypt the session key with my private key" โ”‚
โ”‚ session_key = decrypt(encrypted_key, server_private_key) โ”‚
โ”‚ "Great! Now we both have the same secret key" โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Step 7: Secure Communication Established โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Both Client and Server: โ”‚
โ”‚ "All future data will be encrypted with session_key" โ”‚
โ”‚ โ”‚
โ”‚ Client: encrypt(data, session_key) โ†’ Server โ”‚
โ”‚ Server: decrypt(data, session_key) โ†’ process โ”‚
โ”‚ Server: encrypt(response, session_key) โ†’ Client โ”‚
โ”‚ Client: decrypt(response, session_key) โ†’ display โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Result: All communication is now encrypted! ๐Ÿ”’

What Your Code Sees vs What TLS Seesโ€‹

Your Java Code (unchanged):

@PostMapping("/auth/login")
public ResponseEntity<LoginResponse> login(@RequestBody LoginRequest request) {
// You receive plain text here
String email = request.getEmail(); // "test@example.com"
String password = request.getPassword(); // "testpass123"

// Your code works exactly the same!
User user = userRepository.findByEmail(email).orElseThrow(...);
if (passwordEncoder.matches(password, user.getPassword())) {
return ResponseEntity.ok(new LoginResponse(...));
}
throw new RuntimeException("Invalid credentials");
}

What TLS Does (automatically, behind the scenes):

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ 1. Incoming Request (from network) โ”‚
โ”‚ Encrypted: ๏ฟฝ๏ฟฝk๏ฟฝ๏ฟฝvT๏ฟฝ8o๏ฟฝ๏ฟฝP๏ฟฝ๏ฟฝ๏ฟฝ1๏ฟฝG๏ฟฝ๏ฟฝ... โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 2. TLS Layer Decrypts โ”‚
โ”‚ Decrypted: {"email": "test@...", "password": "pass123"} โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 3. Your Code Receives Plain Text โ”‚
โ”‚ request.getPassword() = "testpass123" โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 4. Your Code Processes and Returns Response โ”‚
โ”‚ return ResponseEntity.ok(new LoginResponse(...)); โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 5. TLS Layer Encrypts Response โ”‚
โ”‚ Encrypted: ๏ฟฝ๏ฟฝX๏ฟฝ๏ฟฝ3f๏ฟฝ๏ฟฝY๏ฟฝ๏ฟฝ๏ฟฝ2๏ฟฝP๏ฟฝ๏ฟฝ... โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 6. Outgoing Response (to network) โ”‚
โ”‚ Encrypted: ๏ฟฝ๏ฟฝX๏ฟฝ๏ฟฝ3f๏ฟฝ๏ฟฝY๏ฟฝ๏ฟฝ๏ฟฝ2๏ฟฝP๏ฟฝ๏ฟฝ... โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

You write zero encryption code! It's all handled by Tomcat + Java's security libraries + operating system.

The Certificate and Keysโ€‹

What's in keystore.p12:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ SSL Certificate (keystore.p12) โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ โ”‚
โ”‚ 1. Public Key โ”‚
โ”‚ - Shared with clients during TLS handshake โ”‚
โ”‚ - Used by clients to encrypt session key โ”‚
โ”‚ - Safe to share publicly โ”‚
โ”‚ โ”‚
โ”‚ 2. Private Key โ”‚
โ”‚ - Kept secret by server โ”‚
โ”‚ - Used to decrypt session key from client โ”‚
โ”‚ - NEVER shared with anyone โ”‚
โ”‚ โ”‚
โ”‚ 3. Certificate Metadata โ”‚
โ”‚ - Domain: localhost โ”‚
โ”‚ - Valid from: 2025-01-01 โ”‚
โ”‚ - Valid until: 2026-01-01 โ”‚
โ”‚ - Issued by: Self-signed (for development) โ”‚
โ”‚ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Configuration Triggers the Magicโ€‹

In application.properties:

server.ssl.enabled=true                          # โ† Activates HTTPS
server.ssl.key-store=classpath:keystore.p12 # โ† Certificate location
server.ssl.key-store-password=changeit # โ† Keystore password
server.ssl.key-store-type=PKCS12 # โ† Certificate format

What happens when Spring Boot starts:

1. Spring Boot reads application.properties
โ†“
2. Sees server.ssl.enabled=true
โ†“
3. Tells Tomcat: "Enable HTTPS on port 8443"
โ†“
4. Tomcat loads keystore.p12
โ†“
5. Tomcat extracts public key + private key
โ†“
6. Tomcat configures TLS/SSL protocol
โ†“
7. Tomcat starts listening on HTTPS port
โ†“
8. Application ready: https://localhost:8443 โœ…

Why It's "Magic"โ€‹

You don't write any of this code:

// โŒ You DON'T write this (TLS does it automatically)
String encryptedPassword = TLS.encrypt(request.getPassword());
String decryptedPassword = TLS.decrypt(encryptedPassword);

Instead, you write this:

// โœ… You write this (exactly the same as HTTP)
@PostMapping("/auth/login")
public ResponseEntity<LoginResponse> login(@RequestBody LoginRequest request) {
String password = request.getPassword(); // Already decrypted by TLS!
// ... your business logic
}

The magic:

  • โœ… Encryption/decryption handled by TLS layer
  • โœ… Your code stays simple and unchanged
  • โœ… No performance impact on your business logic
  • โœ… Industry-standard security automatically applied

Performance Impactโ€‹

TLS handshake: ~100ms (one-time per connection) Encryption/decryption: ~1-5ms per request (negligible)

Total overhead: Minimal, worth it for security!


Configuring HTTPS in Spring Bootโ€‹

Step 1: Generate SSL Certificateโ€‹

For development (self-signed certificate):

keytool -genkeypair \
-alias tomcat \
-keyalg RSA \
-keysize 2048 \
-keystore keystore.p12 \
-validity 365 \
-storetype PKCS12 \
-storepass changeit

What this creates:

  • File: keystore.p12 (SSL certificate)
  • Type: PKCS12 (standard format)
  • Valid for: 365 days
  • Password: changeit

Move it to your project:

mv keystore.p12 src/main/resources/

Step 2: Configure application.propertiesโ€‹

# Server Configuration
server.port=8443

# SSL/TLS Configuration
server.ssl.enabled=true
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password=changeit
server.ssl.key-store-type=PKCS12
server.ssl.key-alias=tomcat

# Force HTTPS
server.ssl.protocol=TLS
server.ssl.enabled-protocols=TLSv1.2,TLSv1.3

Step 3: Access via HTTPSโ€‹

Before:

http://localhost:8082/api/auth/login  โŒ Insecure

After:

https://localhost:8443/api/auth/login  โœ… Secure

Security Best Practicesโ€‹

1. โœ… Always Use HTTPS in Productionโ€‹

# Production
server.ssl.enabled=true

Never deploy to production without HTTPS!

Get free SSL certificates:

  • Let's Encrypt - Free automated certificates
  • Certbot - Automatic renewal
  • Cloud providers (AWS, Azure, GCP) - Managed certificates

2. โœ… Hash Passwords (You're Already Doing This!)โ€‹

@Service
public class AuthService {

@Autowired
private PasswordEncoder passwordEncoder;

public void register(RegisterRequest request) {
User user = new User();
user.setEmail(request.getEmail());
user.setPassword(passwordEncoder.encode(request.getPassword())); // โœ… Hashed!
userRepository.save(user);
}
}

Password flow:

Client sends: "testpass123"
โ†“ (HTTPS encryption during transit)
Server receives: "testpass123"
โ†“ (BCrypt hashing)
Database stores: "$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy"

Even if database is compromised:

  • โŒ Attacker gets hash: $2a$10$N9qo8...
  • โŒ Cannot reverse hash to get testpass123
  • โœ… Password remains secure

3. โœ… Never Log Passwordsโ€‹

// โŒ NEVER DO THIS
@PostMapping("/auth/login")
public ResponseEntity<LoginResponse> login(@RequestBody LoginRequest request) {
log.info("Login attempt: email={}, password={}",
request.getEmail(),
request.getPassword()); // โŒ DANGEROUS!
// ...
}

// โœ… CORRECT
@PostMapping("/auth/login")
public ResponseEntity<LoginResponse> login(@RequestBody LoginRequest request) {
log.info("Login attempt: email={}", request.getEmail()); // โœ… Safe
// Password never logged
}

4. โœ… Use Secure Headersโ€‹

@Configuration
@EnableWebSecurity
public class SecurityConfig {

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.headers()
.httpStrictTransportSecurity() // Force HTTPS
.maxAgeInSeconds(31536000) // 1 year
.includeSubDomains(true)
.and()
.contentSecurityPolicy("default-src 'self'");

return http.build();
}
}

HSTS Header:

Strict-Transport-Security: max-age=31536000; includeSubDomains

What it does:

  • Forces browser to ALWAYS use HTTPS
  • Even if user types http://, browser converts to https://
  • Prevents SSL stripping attacks

5. โœ… Use JWT Tokens After Loginโ€‹

Don't send password on every request!

// โŒ WRONG: Send password on every request
@GetMapping("/api/profile")
public UserResponse getProfile(@RequestBody LoginRequest request) {
// Validates password every time
}

// โœ… CORRECT: Send JWT token after login
@GetMapping("/api/profile")
public UserResponse getProfile(@RequestHeader("Authorization") String token) {
// Validates token (no password needed)
}

Login flow:

1. Client sends: { "email": "...", "password": "..." }
2. Server validates credentials
3. Server generates JWT token
4. Server returns: { "token": "eyJhbGciOiJIUzI1..." }
5. Client stores token
6. Future requests: Authorization: Bearer eyJhbGciOiJIUzI1...
7. No password sent after initial login

When to Use Whatโ€‹

Development (Local Testing)โ€‹

# HTTP is acceptable for local development
server.port=8082
server.ssl.enabled=false

Acceptable because:

  • Traffic never leaves your machine
  • No network to intercept
  • Faster development (no certificate setup)

Staging/Productionโ€‹

# HTTPS is MANDATORY
server.port=8443
server.ssl.enabled=true
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password=${SSL_PASSWORD} # From environment variable

Required because:

  • Traffic goes through public internet
  • Real user credentials at risk
  • Compliance requirements (GDPR, PCI-DSS)

Testing HTTPS Locallyโ€‹

Using Postmanโ€‹

Self-signed certificate warning:

Settings โ†’ General โ†’ SSL certificate verification โ†’ OFF

Make request:

POST https://localhost:8443/api/auth/login
Headers:
Content-Type: application/json

Body:
{
"email": "testuser@example.com",
"password": "testpass123"
}

Using cURLโ€‹

# Accept self-signed certificate
curl -k -X POST https://localhost:8443/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "testuser@example.com",
"password": "testpass123"
}'

Using Browserโ€‹

https://localhost:8443/api/auth/login

Browser warning:

โš ๏ธ Your connection is not private
This site uses a self-signed certificate

[Advanced] โ†’ [Proceed to localhost (unsafe)]

Accept for development only!


The Complete Security Stackโ€‹

Layer 1: HTTPS (Transport Security)โ€‹

Encrypts data in transit
Prevents network interception

Layer 2: Password Hashing (Storage Security)โ€‹

passwordEncoder.encode(request.getPassword())
// Plain: "testpass123"
// Hashed: "$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy"

Layer 3: JWT Tokens (Session Security)โ€‹

// After login, use tokens instead of passwords
String token = jwtService.generateToken(user);
// Future requests use token, not password

Layer 4: Spring Security (Authorization)โ€‹

http
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated();

Real-World Attack Scenariosโ€‹

Scenario 1: Coffee Shop WiFi (HTTP)โ€‹

Setup:

  • You're at Starbucks
  • Connected to public WiFi
  • Your app uses HTTP

Attack:

Your Laptop
โ†“ (sends password in plain text)
WiFi Router
โ†“ (hacker captures packet)
Hacker's Wireshark
โœ“ Sees: "testpass123"

Result: Account compromised! ๐Ÿšจ

Scenario 2: Coffee Shop WiFi (HTTPS)โ€‹

Setup:

  • You're at Starbucks
  • Connected to public WiFi
  • Your app uses HTTPS

Attack:

Your Laptop
โ†“ (sends encrypted password)
WiFi Router
โ†“ (hacker captures packet)
Hacker's Wireshark
โœ— Sees: "๏ฟฝ๏ฟฝk๏ฟฝ๏ฟฝvT๏ฟฝ8o๏ฟฝ๏ฟฝP"

Result: Password safe! โœ…

Scenario 3: Man-in-the-Middle Attackโ€‹

HTTP (vulnerable):

Client โ†’ Attacker โ†’ Server
(intercepts and reads everything)

HTTPS (protected):

Client โ†’ Attacker โ†’ Server
(sees encrypted data only)
(cannot decrypt without private key)

Common Misconceptionsโ€‹

โŒ "Password hashing is enough"โ€‹

Wrong!

Hashing protects stored passwords, not transmitted passwords.

HTTP + Hashing:
Client: "password123" (plain text in transit) โ†’ Network sees: "password123"
Server: hashes to "$2a$10$..." โ†’ Database stores hash

Attacker intercepts: "password123" โœ“ Can login!

HTTPS + Hashing:

HTTPS + Hashing:
Client: "password123" โ†’ Encrypted to "๏ฟฝ๏ฟฝk๏ฟฝ๏ฟฝvT" โ†’ Network sees: "๏ฟฝ๏ฟฝk๏ฟฝ๏ฟฝvT"
Server: decrypts, hashes to "$2a$10$..." โ†’ Database stores hash

Attacker intercepts: "๏ฟฝ๏ฟฝk๏ฟฝ๏ฟฝvT" โœ— Cannot decrypt or use!

โŒ "Only big companies need HTTPS"โ€‹

Wrong!

ALL websites handling passwords need HTTPS:
- Personal blogs with login
- Small e-commerce sites
- Internal corporate apps
- Student projects (if deployed publicly)

โŒ "HTTPS is expensive"โ€‹

Wrong!

Free options:
- Let's Encrypt (free certificates)
- Cloudflare (free SSL)
- Cloud providers (often included)

Summaryโ€‹

The Questionโ€‹

"Is it safe to send passwords in LoginRequest? Can someone intercept it?"

The Answerโ€‹

It depends on HTTP vs HTTPS:

ProtocolSafetyCan Be Intercepted?
HTTPโŒ Unsafeโœ… Yes (plain text)
HTTPSโœ… SafeโŒ No (encrypted)

Security Layersโ€‹

Layer 1: HTTPS           โ†’ Protects transmission (network security)
Layer 2: Password Hash โ†’ Protects storage (database security)
Layer 3: JWT Tokens โ†’ Protects sessions (authentication security)
Layer 4: Spring Security โ†’ Protects endpoints (authorization security)

Quick Referenceโ€‹

Development (localhost):

server.ssl.enabled=false  # HTTP is acceptable

Production:

server.ssl.enabled=true   # HTTPS is MANDATORY
server.ssl.key-store=classpath:keystore.p12

Best Practices:

  1. โœ… Always use HTTPS in production
  2. โœ… Hash passwords with BCrypt/Argon2
  3. โœ… Never log passwords
  4. โœ… Use secure headers (HSTS)
  5. โœ… Use JWT tokens after login (don't send password repeatedly)

Bottom line: HTTPS encrypts passwords during transmission. Password hashing protects stored passwords. You need BOTH for complete security. Never deploy to production without HTTPS! ๐Ÿ”’