DEV Community

Mudit Garg
Mudit Garg

Posted on • Edited on

System Design - Authentication

For JWT Token:

Best Practices :

  • Rate Limiting
  • Access & Refresh token
  • Exponential Backoff
  • Token Blacklist / Rotation Strategy
  • hashed passwords (Argon2)

What if Token get stole ??
solution - Use access & Refresh Token

If someone change password on one device then what about others ??
solution - Invalidate all sessions when password is changed

**

Login - Rate Limiting Strategy

**
Layer 1: IP-based limiting (prevents brute force from single source)
Layer 2: Username/Email-based limiting (protects specific accounts)
Layer 3: Progressive penalties with exponential backoff

IP-based limiting ->
Token Bucket

Key: IP address
Value: { tokens, last_refill_timestamp }
Enter fullscreen mode Exit fullscreen mode

so we have decided to start with
Token : 10
1 token every 6 second

For new user
no entry exist for IP so create one

IP : { tokens: 10, last_refill_timestamp: 1:00 }
Enter fullscreen mode Exit fullscreen mode

user made a request

IP : { tokens: 9, last_refill_timestamp: 1:00 }
Enter fullscreen mode Exit fullscreen mode

Now within 3 sec user has used all 10 tokens
for his 11 request at 1:03
count tokens using last_refill_timestamp
current_time - last_refill_timestamp = 3sec
No of new Tokens = 3/6 = 0;
as Total Tokens are 0 return 429(Too Many Request)

at 7second user made a new request so calculate token
and refill it update last_refill_timestamp.

Access Token & Refresh Token

Access Token -> short-lived
Refresh Token -> long-lived

On log-in
create both tokens & return them

user will send access token with every request & backend will verify it, if access-token got invalid return 401(unauthorized)
and then client made a new call on seeing 401 by sending refresh- token for new access-token, if refresh-token valid then fine return new access-token else clear local-storage data, redirect to login, Cancel ongoing requests, and show message Login again

Exponential Backoff
When a client keeps sending failed/invalid requests, the server forces the client to wait longer and longer before retrying.
2 attempts -> 1sec
3 attempts -> 2sec
4 attempts -> 4sec
5 attempts -> 8sec

Apply Exponential Backoff only on login when credential fails means invalid request.
after rateLimiterMiddleware procees to AuthService in Authservice check whether for that user BackOff is active or not
if active -> return 429, Too many Failed Attempts
else validate credentials
if success -> reset backoff counter
if failure -> increment failure counter

Algorithm
delay = baseDelay * 2^failCount
nextAllowedTime = currentTime + delay

Redis will store

  1. Failure counter - backoff:failCount:user@gmail.com = 3
  2. Next allowed login timestamp - backoff:nextAllowed:user@gmail.com = 1732918400 Redis keys should expire automatically using TTL, on TTL expires both objects got deleted or on Successfull Login
login_backOff:user@gmail.com : { failCount: '',
                                nextAllowed: ''}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)