Files
sriphat-dataplatform/03-apiservice/KEYCLOAK-SETUP.md

326 lines
7.9 KiB
Markdown

# Keycloak Setup Guide for API Service Authentication
## Prerequisites
1. Keycloak must be running at `http://localhost:8085`
2. PostgreSQL database must have `keycloak` database created
3. API Service must have Keycloak configuration in `.env`
## Step 1: Restart Infrastructure to Create Keycloak Database
```bash
cd 01-infra
docker compose down
docker compose --env-file ../.env.global up -d
```
Wait for Keycloak to initialize (check logs):
```bash
docker logs keycloak -f
```
Look for: `Keycloak ... started`
## Step 2: Access Keycloak Admin Console
1. Open browser: `http://localhost:8085/admin`
2. Login credentials:
- **Username**: `admin`
- **Password**: `admin_secret_pass_2026`
## Step 3: Create Client for API Service
### 3.1 Navigate to Clients
1. In left sidebar, click **Clients**
2. Click **Create client** button
### 3.2 General Settings
- **Client type**: `OpenID Connect`
- **Client ID**: `apiservice`
- Click **Next**
### 3.3 Capability Config
- **Client authentication**: `ON` (toggle to enable)
- **Authorization**: `OFF`
- **Authentication flow**:
- ✅ Standard flow
- ✅ Direct access grants
- ❌ Implicit flow (uncheck)
- ❌ Service accounts roles (uncheck)
- Click **Next**
### 3.4 Login Settings
Fill in the following URLs:
**Root URL**:
```
http://localhost:8040
```
**Home URL**:
```
http://localhost:8040/apiservice/
```
**Valid redirect URIs** (add both):
```
http://localhost:8040/apiservice/auth/callback
https://ai.sriphat.com/apiservice/auth/callback
```
**Valid post logout redirect URIs** (add both):
```
http://localhost:8040/apiservice/
https://ai.sriphat.com/apiservice/
```
**Web origins** (add both):
```
http://localhost:8040
https://ai.sriphat.com
```
Click **Save**
### 3.5 Get Client Secret
1. Go to **Credentials** tab
2. Copy the **Client secret** value
3. Save it - you'll need it for the `.env` file
## Step 4: Configure API Service
### 4.1 Create/Update `.env` file in `03-apiservice`
```bash
cd ../03-apiservice
```
Create `.env` file with:
```bash
# Application
APP_NAME=APIsService
ROOT_PATH=/apiservice
# Timezone
TIMEZONE=Asia/Bangkok
# PostgreSQL Database
DB_HOST=postgres
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=Secure_Hospital_Pass_2026
DB_NAME=postgres
DB_SSLMODE=prefer
# Supabase (if not using, keep dummy values)
SUPABASE_DB_HOST=localhost
SUPABASE_DB_PORT=5432
SUPABASE_DB_USER=postgres
SUPABASE_DB_PASSWORD=dummy
SUPABASE_DB_NAME=postgres
SUPABASE_DB_SSLMODE=disable
SUPABASE_API_URL=http://localhost:8000
SUPABASE_API_KEY=dummy
# Admin Authentication
ADMIN_SECRET_KEY=apiservice_admin_secret_2026
ADMIN_USERNAME=admin
ADMIN_PASSWORD=change_me_2026
# API Key Encryption
API_KEY_ENC_SECRET=dev_encryption_secret_2026
# Keycloak Authentication
KEYCLOAK_SERVER_URL=http://keycloak:8080
KEYCLOAK_REALM=master
KEYCLOAK_CLIENT_ID=apiservice
KEYCLOAK_CLIENT_SECRET=<PASTE_YOUR_CLIENT_SECRET_HERE>
KEYCLOAK_REDIRECT_URI=http://localhost:8040/apiservice/auth/callback
```
**Important**: Replace `<PASTE_YOUR_CLIENT_SECRET_HERE>` with the actual secret from Step 3.5
## Step 5: Create Test User in Keycloak
### 5.1 Create User
1. In Keycloak Admin, go to **Users**
2. Click **Add user**
3. Fill in:
- **Username**: `testuser`
- **Email**: `test@sriphat.local`
- **First name**: `Test`
- **Last name**: `User`
- **Email verified**: `ON` (toggle)
4. Click **Create**
### 5.2 Set Password
1. Go to **Credentials** tab
2. Click **Set password**
3. Fill in:
- **Password**: `password`
- **Password confirmation**: `password`
- **Temporary**: `OFF` (toggle off)
4. Click **Save**
5. Confirm by clicking **Save password**
## Step 6: Rebuild and Restart API Service
```bash
cd 03-apiservice
docker compose down
docker compose --env-file ../.env up --build -d
```
Check logs:
```bash
docker logs apiservice -f
```
Look for successful startup without errors.
## Step 7: Test Authentication Flow
### 7.1 Access Landing Page
1. Open browser: `http://localhost:8040/apiservice/`
2. You should be redirected to Keycloak login page
### 7.2 Login
1. Enter credentials:
- **Username**: `testuser`
- **Password**: `password`
2. Click **Sign In**
### 7.3 Verify Success
1. You should be redirected back to the landing page
2. You should see your name in the top-right corner: "👤 Test User"
3. You should see a **Logout** button
### 7.4 Test Protected Pages
Try accessing:
- `/apiservice/` - Landing page (requires auth)
- `/apiservice/docs` - API docs (requires auth)
- `/apiservice/data-management/finance` - Finance page (requires auth)
All should work without redirecting to login again.
### 7.5 Test API Endpoints (Should NOT require Keycloak auth)
```bash
# API endpoints use API Key authentication, not Keycloak
curl -X GET http://localhost:8040/apiservice/api/v1/health
```
This should work without Keycloak authentication.
### 7.6 Test Logout
1. Click **Logout** button
2. You should be logged out from Keycloak
3. Accessing any protected page should redirect to login again
## Troubleshooting
### Error: "access_denied" in Keycloak logs
**Cause**: Client not configured correctly or client secret mismatch
**Solution**:
1. Verify client ID is exactly `apiservice`
2. Verify client secret in `.env` matches Keycloak
3. Verify redirect URIs are correct
4. Restart API service after changing `.env`
### Error: "SessionMiddleware must be installed"
**Cause**: Middleware order is incorrect
**Solution**: Already fixed in `app/main.py` - SessionMiddleware is added after WebAuthenticationMiddleware
### Error: "Invalid redirect_uri"
**Cause**: Redirect URI not in Keycloak's allowed list
**Solution**:
1. Go to Keycloak → Clients → apiservice → Settings
2. Add the exact redirect URI to "Valid redirect URIs"
3. Make sure it matches `KEYCLOAK_REDIRECT_URI` in `.env`
### Error: Connection refused to Keycloak
**Cause**: Keycloak not running or wrong URL
**Solution**:
1. Check Keycloak is running: `docker ps | grep keycloak`
2. Verify `KEYCLOAK_SERVER_URL=http://keycloak:8080` (use container name, not localhost)
3. Verify both services are on same Docker network
## Production Deployment
For production deployment:
1. **Use HTTPS**:
```bash
KEYCLOAK_REDIRECT_URI=https://ai.sriphat.com/apiservice/auth/callback
```
2. **Update Keycloak Client**:
- Add production redirect URIs
- Remove localhost URIs
3. **Secure Cookies**:
- SessionMiddleware should use `secure=True, httponly=True, samesite='lax'`
4. **Use Nginx Proxy Manager**:
- Configure SSL certificates
- Set up proper reverse proxy rules
5. **Environment Variables**:
- Use Docker secrets or external secret management
- Never commit `.env` with real secrets to git
## Security Notes
1. **Client Secret**: Keep this secret! Never commit to git
2. **Session Secret**: Use strong random value for `ADMIN_SECRET_KEY`
3. **HTTPS**: Always use HTTPS in production
4. **Token Expiration**: Configure appropriate token lifetimes in Keycloak
5. **CORS**: Restrict `allow_origins` to known domains only
## Architecture
```
User Browser
↓ (1) Access protected page
API Service (FastAPI)
↓ (2) Check session - not authenticated
↓ (3) Redirect to Keycloak login
Keycloak (OAuth2/OIDC)
↓ (4) User enters credentials
↓ (5) Redirect back with auth code
API Service
↓ (6) Exchange code for tokens
↓ (7) Store user info in session
↓ (8) Redirect to original page
User sees protected page with user info
```
## API vs Web Authentication
| Type | Authentication Method | Protected Routes |
|------|----------------------|------------------|
| **Web Pages** | Keycloak (OAuth2/OIDC) | `/`, `/docs`, `/data-management/*` |
| **API Endpoints** | API Key (Bearer Token) | `/api/v1/*` |
| **Admin Panel** | SQLAdmin (Basic Auth) | `/admin/*` |
This separation allows:
- Human users to login via Keycloak for web UI
- Applications/services to use API Keys for programmatic access
- Admins to manage API keys via separate admin panel