← Back to Questions
JWT

what is jwt?

Learn what is jwt? with simple explanations, real-time examples, interview tips and practical use cases.

JWT stands for JSON Web Token. In a banking project, JWT is used to identify a logged-in customer securely when they access APIs like balance enquiry, fund transfer, statement download, loan details, and profile information.

Real-Time Banking Example

Suppose customer Naresh logs into a banking application. After successful login, the backend generates an Access Token and a Refresh Token.

1. Login Request

The customer enters username and password:

{
  "username": "naresh",
  "password": "123456"
}

The frontend sends this request to backend:

POST /bank/auth/login

2. Backend Validates User

The backend checks whether the username and password are valid by comparing them with the user details stored in the database.

Username: naresh
Password: 123456

Database check:
User exists? YES
Password valid? YES
Account active? YES

3. Backend Generates Tokens

After successful validation, the backend generates two tokens:

Token Purpose Expiry
Access Token Used to access protected APIs 5 to 15 minutes
Refresh Token Used to generate a new access token 1 day to 7 days

4. Login Response

The backend returns tokens to the frontend:

{
  "accessToken": "eyJhbGciOiJIUzI1NiJ9.access.token",
  "refreshToken": "eyJhbGciOiJIUzI1NiJ9.refresh.token"
}

5. JWT Payload Example

A JWT contains user information called claims. In banking, only non-sensitive data should be stored inside JWT.

{
  "sub": "naresh",
  "customerId": "CUST1001",
  "role": "CUSTOMER",
  "iat": 1715151000,
  "exp": 1715151900
}

Never Store Sensitive Data in JWT

Do not store password, PIN, OTP, CVV, account balance, or full card number inside JWT.

6. Client Stores Token

In normal projects, tokens are often stored in localStorage. But in banking applications, the recommended approach is to store tokens in HttpOnly Secure Cookies.

Set-Cookie: accessToken=jwt_access_token;
HttpOnly;
Secure;
SameSite=Strict

HttpOnly cookies are safer because JavaScript cannot directly read the token.

7. Accessing Protected API

When the customer clicks on Check Balance, the frontend sends the access token to the backend.

GET /bank/accounts/balance
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.access.token

8. JWT Filter Validates Token

Before the request reaches the controller, a JWT filter checks whether the token is valid.

JWT Filter Steps:

1. Read Authorization header
2. Extract Bearer token
3. Validate token signature
4. Check token expiry
5. Extract username and customerId
6. Create Authentication object
7. Store authentication in SecurityContext
8. Allow request to controller

9. Signature Validation

JWT has three parts:

HEADER.PAYLOAD.SIGNATURE

If someone changes the payload, for example changing role from CUSTOMER to ADMIN, the signature becomes invalid and backend rejects the token.

{
  "role": "CUSTOMER"
}

If changed illegally:

{
  "role": "ADMIN"
}

The backend detects tampering and returns:

401 Unauthorized

10. Expiry Validation

Access tokens should have short expiry in banking applications.

Access token expiry: 10 minutes

If the token is expired, backend rejects the request.

401 Unauthorized - Token Expired

11. Controller Receives Authenticated User

After token validation, Spring Security stores user details in SecurityContext. Then the controller can access the logged-in user.

@GetMapping("/accounts/balance")
public BalanceResponse getBalance(Authentication authentication) {

    BankingUserPrincipal user =
            (BankingUserPrincipal) authentication.getPrincipal();

    return accountService.getBalance(user.getCustomerId());
}

12. Account Ownership Validation

JWT proves that the user is logged in. But the backend must still verify whether the requested account belongs to that customer.

Customer ID from JWT: CUST1001
Requested account: ACC1001

Database check:
Does ACC1001 belong to CUST1001? YES

If customer tries another account:

Customer ID from JWT: CUST1001
Requested account: ACC9999

Database check:
Does ACC9999 belong to CUST1001? NO

Response:
403 Forbidden

13. Fund Transfer Example

Customer sends a fund transfer request:

POST /bank/transfer
Authorization: Bearer access_token
{
  "fromAccount": "ACC1001",
  "toAccount": "ACC2001",
  "amount": 5000
}

Backend validations:

1. JWT valid?
2. Token not expired?
3. Customer owns fromAccount?
4. Account active?
5. Balance available?
6. Daily transfer limit valid?
7. OTP verified?
8. Process transfer

14. OTP Verification

For sensitive banking operations like fund transfer, JWT alone is not enough. OTP verification is required.

Transfer Flow:

1. Customer enters transfer details
2. Backend generates OTP
3. OTP sent to mobile/email
4. Customer enters OTP
5. Backend validates OTP
6. Transfer completed

15. Transaction Processing

Money transfer should be done inside a database transaction. If debit succeeds but credit fails, the transaction must rollback.

@Transactional
public TransferResponse transferMoney(TransferRequest request) {

    debitFromSenderAccount();

    creditToReceiverAccount();

    saveTransactionHistory();

    return new TransferResponse("SUCCESS", "Transfer completed");
}

16. Refresh Token Flow

Access tokens expire quickly. So, when the access token expires, the frontend uses the refresh token to get a new access token without asking the user to login again.

Access Token Expired
        |
        v
Frontend calls /auth/refresh
        |
        v
Backend validates refresh token
        |
        v
Backend generates new access token
        |
        v
Frontend continues API usage

17. Refresh Token API Example

POST /bank/auth/refresh
{
  "refreshToken": "eyJhbGciOiJIUzI1NiJ9.refresh.token"
}

Backend response:

{
  "accessToken": "new_access_token_here"
}

18. Refresh Token Backend Logic

public TokenResponse refreshToken(String refreshToken) {

    if (!jwtService.isValid(refreshToken)) {
        throw new RuntimeException("Invalid refresh token");
    }

    String username = jwtService.extractUsername(refreshToken);

    User user = userRepository.findByUsername(username)
            .orElseThrow();

    String newAccessToken = jwtService.generateAccessToken(user);

    return new TokenResponse(newAccessToken);
}

19. Access Token vs Refresh Token

Point Access Token Refresh Token
Purpose Access protected APIs Generate new access token
Expiry Short Longer
Sent with every request? Yes No
Risk if stolen Medium High
Storage HttpOnly Cookie HttpOnly Cookie or secure DB-backed token

20. Logout Flow

JWT is stateless. So logout should clear tokens and invalidate refresh tokens.

Logout Flow:

1. User clicks logout
2. Backend deletes refresh token from DB
3. Access token can be blacklisted in Redis
4. Browser cookies are cleared
5. User redirected to login page

21. Refresh Token Storage in Database

In production banking applications, refresh tokens are usually stored in database or Redis so they can be revoked.

refresh_tokens table

id | user_id | token_hash | expiry_date | revoked
1  | 101     | hash_value | 2026-05-18  | false

22. Full Banking JWT Flow

1. Customer logs in
2. Backend validates username and password
3. Backend generates access token and refresh token
4. Frontend stores tokens securely
5. Customer calls balance or transfer API
6. Access token is sent with request
7. JWT filter validates token
8. Backend extracts customerId and role
9. Service checks account ownership
10. OTP validation happens for transfer
11. Transaction is processed
12. Audit log is saved
13. Response returned to customer
14. If access token expires, refresh token generates new access token
15. On logout, refresh token is revoked

23. Banking Security Best Practices

  • Use HTTPS only.
  • Keep access token expiry short.
  • Store tokens in HttpOnly Secure cookies.
  • Never store password, PIN, OTP, or card details in JWT.
  • Validate account ownership in service layer.
  • Use OTP or MFA for fund transfers.
  • Store refresh tokens in DB or Redis.
  • Revoke refresh token on logout.
  • Use Redis blacklist for high-security logout handling.
  • Log all sensitive banking actions.

24. Simple Interview Explanation

In my banking project, after successful login, the backend generates an access token and a refresh token. The access token contains basic claims like username, customerId, and role. The frontend sends the access token with every protected API request. A JWT filter validates the token, extracts the customer details, and stores authentication in SecurityContext. For banking operations like balance enquiry and fund transfer, the backend also verifies account ownership from the database. For fund transfer, OTP validation, balance check, transaction limit check, and audit logging are also performed. When the access token expires, the refresh token is used to generate a new access token. On logout, the refresh token is revoked.

Why this JWT question is important?

This interview question helps candidates understand real-time backend development concepts, practical problem solving, coding fundamentals, system design basics and production-ready application behavior.

Practice this question carefully for Java backend roles, Spring Boot developer interviews, microservices interviews, company interviews and full-stack developer preparation.

About the Author

Naresh Kumar is a Senior Java Backend Engineer with experience building enterprise applications using Java, Spring Boot, Microservices, Docker, Kubernetes and Cloud technologies.