7.9 KiB
Keycloak Setup Guide for API Service Authentication
Prerequisites
- Keycloak must be running at
http://localhost:8085 - PostgreSQL database must have
keycloakdatabase created - API Service must have Keycloak configuration in
.env
Step 1: Restart Infrastructure to Create Keycloak Database
cd 01-infra
docker compose down
docker compose --env-file ../.env.global up -d
Wait for Keycloak to initialize (check logs):
docker logs keycloak -f
Look for: Keycloak ... started
Step 2: Access Keycloak Admin Console
- Open browser:
http://localhost:8085/admin - Login credentials:
- Username:
admin - Password:
admin_secret_pass_2026
- Username:
Step 3: Create Client for API Service
3.1 Navigate to Clients
- In left sidebar, click Clients
- 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
- Go to Credentials tab
- Copy the Client secret value
- Save it - you'll need it for the
.envfile
Step 4: Configure API Service
4.1 Create/Update .env file in 03-apiservice
cd ../03-apiservice
Create .env file with:
# 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
- In Keycloak Admin, go to Users
- Click Add user
- Fill in:
- Username:
testuser - Email:
test@sriphat.local - First name:
Test - Last name:
User - Email verified:
ON(toggle)
- Username:
- Click Create
5.2 Set Password
- Go to Credentials tab
- Click Set password
- Fill in:
- Password:
password - Password confirmation:
password - Temporary:
OFF(toggle off)
- Password:
- Click Save
- Confirm by clicking Save password
Step 6: Rebuild and Restart API Service
cd 03-apiservice
docker compose down
docker compose --env-file ../.env up --build -d
Check logs:
docker logs apiservice -f
Look for successful startup without errors.
Step 7: Test Authentication Flow
7.1 Access Landing Page
- Open browser:
http://localhost:8040/apiservice/ - You should be redirected to Keycloak login page
7.2 Login
- Enter credentials:
- Username:
testuser - Password:
password
- Username:
- Click Sign In
7.3 Verify Success
- You should be redirected back to the landing page
- You should see your name in the top-right corner: "👤 Test User"
- 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)
# 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
- Click Logout button
- You should be logged out from Keycloak
- 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:
- Verify client ID is exactly
apiservice - Verify client secret in
.envmatches Keycloak - Verify redirect URIs are correct
- 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:
- Go to Keycloak → Clients → apiservice → Settings
- Add the exact redirect URI to "Valid redirect URIs"
- Make sure it matches
KEYCLOAK_REDIRECT_URIin.env
Error: Connection refused to Keycloak
Cause: Keycloak not running or wrong URL
Solution:
- Check Keycloak is running:
docker ps | grep keycloak - Verify
KEYCLOAK_SERVER_URL=http://keycloak:8080(use container name, not localhost) - Verify both services are on same Docker network
Production Deployment
For production deployment:
-
Use HTTPS:
KEYCLOAK_REDIRECT_URI=https://ai.sriphat.com/apiservice/auth/callback -
Update Keycloak Client:
- Add production redirect URIs
- Remove localhost URIs
-
Secure Cookies:
- SessionMiddleware should use
secure=True, httponly=True, samesite='lax'
- SessionMiddleware should use
-
Use Nginx Proxy Manager:
- Configure SSL certificates
- Set up proper reverse proxy rules
-
Environment Variables:
- Use Docker secrets or external secret management
- Never commit
.envwith real secrets to git
Security Notes
- Client Secret: Keep this secret! Never commit to git
- Session Secret: Use strong random value for
ADMIN_SECRET_KEY - HTTPS: Always use HTTPS in production
- Token Expiration: Configure appropriate token lifetimes in Keycloak
- CORS: Restrict
allow_originsto 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