382 lines
9.6 KiB
Markdown
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
|