Files
CleanArchitecture-template/.brain/03. Design/02. LowLevelDesign/Auth_Token_Flow.md
2026-03-12 15:17:52 +07:00

87 lines
5.0 KiB
Markdown

# Authentication & Token Flow (iYHCT360)
This document describes in detail the Authentication and Token (Access Token / Refresh Token) processing flow based on the project's actual source code. This is the core security framework designed to be reusable (base) across other projects.
---
## 1. Technology Overview & Design Patterns
- **JWT (JSON Web Token)**: Short-lived Access Token containing the user's basic Claims.
- **Refresh Token Storage**: Securely stored in the Database (saving only hashed strings to prevent database leak vulnerabilities).
- **Refresh Token Rotation**: Upon performing a token refresh, the old Refresh Token is revoked, and a completely new Refresh Token is issued (minimizing the risk of theft).
- **Single Active Session**: Each login will revoke all currently Active Refresh Tokens of that User to ensure there is only 1 active session at a time.
### 1.1. JWT Configuration (`appsettings.json`)
System default lifecycles:
- **Access Token**: Lives for 15 minutes.
- **Refresh Token**: Lives for 7 days.
---
## 2. Detailed Processing Flows
### 2.1. Login Flow
**Endpoint**: `POST /api/auth/login`
**Processing Steps**:
1. Client sends a `LoginRequest` containing: `Email` and `Password`.
2. The system searches for the User by Email (only `IsActive` users).
3. Verifies the password (hashing verification via `IPasswordHasher`).
4. The system retrieves the User's corresponding Roles from the database.
5. Generates an **Access Token** containing information (`id`, `roles`, etc.).
6. Generates a random **Refresh Token** string.
7. Ensures Single Active Session: The system queries the db to find and mark all previous active Refresh Tokens of the user (`RevokedAt = null` and not Expired) as revoked (`RevokedAt = DateTimeOffset.UtcNow`).
8. **Hashing the token**: The random Refresh Token string (which is sent to the client only once) is hashed using an algorithm (e.g., `TokenHasher.ComputeHash()`) and ONLY this hash value is saved in the Database along with the IP + UserAgent.
9. Updates the user's `LastLoginAt` and returns the information (Access Token, Refresh Token, Roles, UserType) to the Client.
### 2.2. Token Refresh Flow (Token Rotation)
**Endpoint**: `POST /api/auth/refresh-token`
**Processing Steps**:
1. Client sends both the `AccessToken` (which might be expired) and the `RefreshToken`.
2. The system looks up the Refresh Token in the Database (stored as the hash of the original Refresh Token string) => Verifies existence, check it's not revoked (`RevokedAt == null`), and check it's not expired.
3. Decodes the `AccessToken` using the Extract Claims function to get the `userId`. The `userId` retrieved from the token MUST match the `UserId` owning the Refresh Token.
4. Checks if the User is still `IsActive`.
5. Reloads the user's roles from the Database (if roles have changed while the old token was still valid, the refresh action will incorporate the new `roles` into the next Access Token).
6. Issues a new `AccessToken` and a completely new `RefreshToken`.
7. Manually marks the current Refresh Token as revoked (`RevokedAt = DateTimeOffset.UtcNow`).
8. Saves the hash value of the **new RefreshToken** into the DB with a 7-day expiration.
9. Returns the data to the Client.
### 2.3. Logout Flow
**Endpoint**: `POST /api/auth/logout`
**Processing Steps**:
1. Client sends the `RefreshToken` to the system.
2. The system hashes the incoming token and finds the corresponding record in the DB.
3. Marks that Token as revoked (`RevokedAt = DateTimeOffset.UtcNow`).
4. (Optional: The Client deletes the AccessToken/RefreshToken stored locally on its device).
### 2.4. Password Reset (Forgot password & Reset)
1. **Forgot Password (`POST /api/auth/forgot-password`)**:
- Generates a Raw Token (a `Guid.NewGuid()` string).
- Hashes that Raw Token and saves it into the User's `SecurityStamp` field.
- Concatenates `${user.Id}:{rawToken}`, then applies `Base64 Encode` and returns it (or sends it via Email) to act as the ResetToken.
2. **Reset Password (`POST /api/auth/reset-password`)**:
- `Base64` decodes the token above to extract the `userId` and `rawToken`.
- Finds the User in the db, compares the hash of `rawToken` with the `SecurityStamp`.
- If valid, Hashes the `NewPassword` into the DB. Sets `SecurityStamp = null` (can only be used to change the password once).
- **Security**: Immediately revokes all active Refresh Tokens for this User to forcefully log them out across all devices.
---
## 3. Best Practices Summary Applied in the Backend
- Fully leverage the `TokenHasher` concept: Never store Refresh Tokens, OTP tokens, or Forgot password tokens in direct raw text. If the Database leaks, attackers still cannot use those tokens (similar to hashed passwords).
- Always cross-check: Ensure the Refresh Token genuinely belongs to the `userId` present in the Access Token to prevent cross-token forgery.
- Synchronization: When an Admin changes a User's Password/Roles or a User changes their own password (Reset/Change) -> The system must automatically revoke all Refresh Tokens to force a fresh log-in.