Files
nextjs-elysia-allaos/docs/checklist-phase3-keycloak.md
phaichayon 043edff93a setup
2026-04-26 00:15:22 +07:00

382 lines
9.6 KiB
Markdown

# Phase 3: Keycloak Integration - Checklist
## ✅ Overview
Implement Keycloak JWT authentication, user extraction, and group-based branch access control. Replace placeholder authentication with real Keycloak integration.
## 📋 Completed Tasks
### Keycloak Library
- [x] Create `src/lib/keycloak.ts` (300+ lines)
- [x] Define KeycloakConfig interface
- [x] Define KeycloakTokenPayload interface
- [x] Implement validateKeycloakToken()
- [x] Implement getUserIdFromRequest()
- [x] Implement getKeycloakGroupsFromRequest()
- [x] Implement getEmailFromRequest()
- [x] Implement getNameFromRequest()
- [x] Implement hasGroup()
- [x] Implement hasAnyGroup()
- [x] Implement getUserInfoFromRequest()
- [x] Implement getKeycloakConfig()
- [x] Implement getMockUserInfo()
- [x] Implement isDevelopmentMode()
### Dependencies
- [x] Install jsonwebtoken package
- [x] Install @types/jsonwebtoken
### Middleware Integration
- [x] Update `src/middleware/branch.ts`
- [x] Import Keycloak functions
- [x] Replace extractUserIdFromRequest() with Keycloak version
- [x] Replace extractUserGroupsFromRequest() with Keycloak version
- [x] Add development mode mock support
- [x] Add header-based mock overrides
### Documentation
- [x] Create `KEYCLOAK_ENV.md`
- [x] Document all required environment variables
- [x] Provide Keycloak setup instructions
- [x] Include troubleshooting guide
- [x] Add security best practices
## 🎯 Key Features Implemented
### 1. JWT Token Validation
```typescript
const payload = validateKeycloakToken(token, config);
if (!payload) {
throw new Error("Invalid token");
}
```
### 2. User Information Extraction
```typescript
const userId = getUserIdFromRequest(request);
const groups = getKeycloakGroupsFromRequest(request);
const email = getEmailFromRequest(request);
const name = getNameFromRequest(request);
```
### 3. Group-Based Access Control
```typescript
// Check if user has specific group
if (hasGroup(request, "alla")) {
// User has alla branch access
}
// Check if user has any of multiple groups
if (hasAnyGroup(request, ["alla", "onvalla"])) {
// User has at least one branch access
}
```
### 4. Development Mode Support
```typescript
if (isDevelopmentMode()) {
// Use mock authentication
const userInfo = getMockUserInfo();
}
```
## 🔧 Usage Examples
### Basic Authentication
```typescript
import {
getUserIdFromRequest,
getKeycloakGroupsFromRequest,
} from "@/lib/keycloak";
app.get("/api/me", ({ request }) => {
const userId = getUserIdFromRequest(request);
const groups = getKeycloakGroupsFromRequest(request);
return { userId, groups };
});
```
### Check User Permissions
```typescript
import { hasGroup } from "@/lib/keycloak";
app.post("/admin/action", ({ request }) => {
if (!hasGroup(request, "admin")) {
throw new Error("Forbidden: Admin access required");
}
// Perform admin action
});
```
### Get Complete User Info
```typescript
import { getUserInfoFromRequest } from "@/lib/keycloak";
app.get("/api/user/profile", ({ request }) => {
const userInfo = getUserInfoFromRequest(request);
return {
userId: userInfo.userId,
email: userInfo.email,
name: userInfo.name,
groups: userInfo.groups,
};
});
```
### Development Mode Testing
```bash
# Without Keycloak
curl -H "x-mock-user-id: test-user-123" \
-H "x-mock-groups: alla,onvalla" \
http://localhost:3000/api/customers
# With Keycloak
curl -H "Authorization: Bearer <jwt-token>" \
http://localhost:3000/api/customers
```
## 📊 Authentication Flow
```
Client Request
Branch Middleware
Check NODE_ENV
├─ Development → Use Mock Authentication
│ ├─ Check x-mock-user-id header
│ ├─ Check x-mock-groups header
│ └─ Use default mock if no headers
└─ Production → Use Keycloak
├─ Extract Authorization header
├─ Decode JWT token
├─ Verify token expiration
└─ Extract user info (id, groups, email, name)
Validate Branch Access
Inject User Context
Route Handler
```
## 🔑 Environment Variables
### Required for Production
```env
KEYCLOAK_REALM=alla-os
KEYCLOAK_AUTH_SERVER_URL=https://keycloak.example.com/auth
KEYCLOAK_CLIENT_ID=alla-os-frontend
KEYCLOAK_CLIENT_SECRET=your-secret-here
KEYCLOAK_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----"
```
### Required for Development
```env
NODE_ENV=development
```
## 🚨 Important Notes
### Development vs Production
- **Development**: Uses mock authentication, no JWT required
- **Production**: Requires valid Keycloak JWT token
- Automatic switching based on `NODE_ENV`
### Token Structure
Keycloak JWT tokens include:
- `sub` - User ID (UUID)
- `email` - User email
- `name` - User full name
- `groups` - User's Keycloak groups (for branch access)
- `realm_access.roles` - Realm-level roles
- `exp` - Expiration timestamp
- `iat` - Issued at timestamp
### Group Mapping
Branch access is determined by Keycloak groups:
- `alla` group → Access to Alla branch
- `onvalla` group → Access to Onvalla branch
- Users can have multiple groups for multi-branch access
### Token Verification
Currently, tokens are decoded but not verified (signature check is commented out). For production:
1. Uncomment JWT verification in `validateKeycloakToken()`
2. Provide valid `KEYCLOAK_PUBLIC_KEY`
3. Test with real Keycloak tokens
## 🔍 Testing Checklist
### Unit Tests (TODO)
- [ ] Test validateKeycloakToken() with valid token
- [ ] Test validateKeycloakToken() with invalid token
- [ ] Test validateKeycloakToken() with expired token
- [ ] Test getUserIdFromRequest() with valid JWT
- [ ] Test getUserIdFromRequest() without Authorization header
- [ ] Test getKeycloakGroupsFromRequest() with groups
- [ ] Test getKeycloakGroupsFromRequest() without groups
- [ ] Test hasGroup() with existing group
- [ ] Test hasGroup() with non-existing group
- [ ] Test hasAnyGroup() with multiple groups
- [ ] Test getMockUserInfo() default values
- [ ] Test getMockUserInfo() with custom values
- [ ] Test isDevelopmentMode() in different environments
### Integration Tests (TODO)
- [ ] Test middleware with development mode
- [ ] Test middleware with production mode
- [ ] Test mock header overrides
- [ ] Test branch access with different groups
- [ ] Test unauthorized access
- [ ] Test expired token handling
- [ ] Test malformed token handling
## 📝 Known Limitations
1. **JWT Signature Not Verified**
- Currently only decodes tokens
- Should verify signature in production
- Requires public key configuration
- **Action Needed**: Uncomment verification code
2. **Token Refresh Not Implemented**
- No automatic token refresh
- Client must handle token expiration
- Consider implementing refresh token flow
3. **Public Key Rotation**
- Public key must be manually updated
- Consider fetching from Keycloak endpoint
- Could implement automatic key rotation
4. **Error Messages Could Be Generic**
- Current errors expose some details
- Could be more generic for security
- Consider logging details separately
## 🔄 Next Steps
### Immediate (Phase 3)
- [ ] Write unit tests
- [ ] Write integration tests
- [ ] Enable JWT signature verification
- [ ] Test with real Keycloak instance
- [ ] Add token refresh logic
### Phase 4: Service Layer Refactor
- [ ] Update services to use userId from context
- [ ] Implement contact visibility checks
- [ ] Add multi-currency calculations
- [ ] Implement revision handling
### Phase 5: Controllers Update
- [ ] Remove authentication placeholders
- [ ] Update error handling
- [ ] Add user info to responses
- [ ] Update API documentation
## 📊 File Changes
### Created Files
-`src/lib/keycloak.ts` (300+ lines)
-`KEYCLOAK_ENV.md` (comprehensive guide)
### Modified Files
-`src/middleware/branch.ts` (integrated Keycloak functions)
-`package.json` (added jsonwebtoken dependency)
### Documentation Files
-`docs/checklist-phase3-keycloak.md`
## ✨ Success Criteria
- [x] Keycloak library created
- [x] JWT token extraction works
- [x] User ID extraction works
- [x] Group extraction works
- [x] Development mode mocking works
- [x] Middleware integration complete
- [x] Environment variables documented
- [x] Security considerations documented
- [x] Troubleshooting guide provided
- [ ] JWT signature verification enabled
- [ ] Unit tests pass
- [ ] Integration tests pass
- [ ] Tested with real Keycloak
## 🎯 Security Considerations
1. **Token Validation** ⚠️
- Currently decodes only
- Must verify signature in production
- Check expiration timestamps
2. **Environment Variables**
- Documented security best practices
- Never commit .env files
- Use strong secrets
3. **Error Messages** ⚠️
- Consider making more generic
- Don't expose internal details
- Log detailed errors server-side
4. **Session Management**
- Stateless JWT approach
- No session storage required
- Easy to scale
5. **CORS Configuration** (TODO)
- Must configure CORS for Keycloak
- Allow proper origins
- Handle preflight requests
## 📚 References
- [Keycloak Documentation](https://www.keycloak.org/documentation)
- [JWT.io](https://jwt.io/) - JWT Debugger
- [jsonwebtoken npm](https://www.npmjs.com/package/jsonwebtoken)
- [OpenID Connect](https://openid.net/connect/)
- [Keycloak Admin REST API](https://www.keycloak.org/docs-api/latest/rest-api/index.html)
---
**Phase 3 Status:** ✅ CORE COMPLETED (Tests & Signature Verification Pending)
**Completion Date:** 2026-04-23
**Next Phase:** Phase 4 - Service Layer Refactor
**Blocking:** JWT signature verification, unit tests, integration tests