Skip to content

Commit 4e2feac

Browse files
committed
chore: set up a keycloak based local testing with docker compose
1 parent 94b726c commit 4e2feac

File tree

4 files changed

+315
-0
lines changed

4 files changed

+315
-0
lines changed

DOCKER_DEPLOYMENT.md

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# Docker Deployment (Production-like Local Stack)
2+
3+
This setup runs a production-like environment locally using Docker Compose with:
4+
- **Keycloak** as the OIDC identity provider
5+
- **Next.js app** in production mode with Keycloak authentication
6+
7+
This simulates how the application would run in production with a real identity provider.
8+
9+
## Prerequisites
10+
11+
- Docker and Docker Compose installed
12+
- Ports 3002 and 8080 available
13+
14+
## Quick Start
15+
16+
1. **Start the stack**:
17+
```bash
18+
docker compose up --build
19+
```
20+
21+
2. **Wait for services to be ready**:
22+
- Keycloak: http://localhost:8080 (takes ~30 seconds)
23+
- App: http://localhost:3002
24+
25+
3. **Log in to the app**:
26+
- Click "Sign In with OIDC"
27+
- Username: `test`
28+
- Password: `test`
29+
30+
## Architecture
31+
32+
```
33+
┌─────────────┐ ┌──────────────┐
34+
│ │ │ │
35+
│ Browser │────────▶│ Next.js │
36+
│ │ │ (port 3002)│
37+
└─────────────┘ └───────┬──────┘
38+
39+
│ OIDC Auth
40+
41+
┌──────────────┐
42+
│ │
43+
│ Keycloak │
44+
│ (port 8080)│
45+
└──────────────┘
46+
```
47+
48+
## Configuration
49+
50+
All configuration is done via environment variables in `docker-compose.yml`:
51+
52+
### Keycloak Service
53+
- **Admin Console**: http://localhost:8080/admin
54+
- Username: `admin`
55+
- Password: `admin`
56+
- **Realm**: `toolhive`
57+
- **Pre-configured client**: `toolhive-cloud-ui`
58+
59+
### Next.js App Service
60+
Environment variables:
61+
- `BETTER_AUTH_SECRET`: Auth session encryption key
62+
- `BETTER_AUTH_URL`: Public URL of the app
63+
- `TRUSTED_ORIGINS`: Allowed CORS origins
64+
- `OIDC_ISSUER_URL`: Keycloak realm URL (internal container URL)
65+
- `OIDC_CLIENT_ID`: OAuth client identifier
66+
- `OIDC_CLIENT_SECRET`: OAuth client secret
67+
68+
## Test User
69+
70+
A test user is pre-created in Keycloak:
71+
- **Username**: `test`
72+
- **Email**: `[email protected]`
73+
- **Password**: `test`
74+
- **Name**: Test User
75+
76+
## Keycloak Admin Access
77+
78+
Access the Keycloak admin console to manage users, clients, and settings:
79+
80+
1. Open http://localhost:8080/admin
81+
2. Log in with admin credentials (admin/admin)
82+
3. Select the `toolhive` realm
83+
84+
## Customization
85+
86+
### Adding More Users
87+
88+
1. Access Keycloak admin console
89+
2. Go to Users → Add User
90+
3. Fill in user details
91+
4. Go to Credentials tab and set a password
92+
93+
### Modifying Client Settings
94+
95+
1. Access Keycloak admin console
96+
2. Go to Clients → `toolhive-cloud-ui`
97+
3. Modify settings as needed
98+
4. Remember to update redirect URIs if changing ports
99+
100+
### Changing Environment Variables
101+
102+
Edit `docker-compose.yml` and restart:
103+
```bash
104+
docker compose down
105+
docker compose up --build
106+
```
107+
108+
## Stopping the Stack
109+
110+
```bash
111+
# Stop services
112+
docker compose down
113+
114+
# Stop and remove volumes (resets Keycloak data)
115+
docker compose down -v
116+
```
117+
118+
## Troubleshooting
119+
120+
### Keycloak not starting
121+
- Wait 30-60 seconds for Keycloak to initialize
122+
- Check logs: `docker compose logs keycloak`
123+
124+
### App can't connect to Keycloak
125+
- Ensure both containers are on the same network
126+
- Check `OIDC_ISSUER_URL` uses container name: `http://keycloak:8080`
127+
128+
### Authentication redirects to wrong URL
129+
- Browser uses `http://localhost:3002`
130+
- Container uses `http://keycloak:8080` (internal)
131+
- Ensure redirect URIs in Keycloak match `http://localhost:3002/api/auth/oauth2/callback/oidc`
132+
133+
## Production Deployment
134+
135+
For actual production deployment:
136+
137+
1. **Use a proper database** for Keycloak (PostgreSQL, MySQL)
138+
2. **Enable HTTPS** with proper certificates
139+
3. **Use strong secrets** - generate with `openssl rand -base64 32`
140+
4. **Configure proper hostname** in Keycloak settings
141+
5. **Remove dev mode** from Keycloak command
142+
6. **Set up persistent volumes** for Keycloak data
143+
7. **Configure proper CORS** origins
144+
8. **Use Kubernetes/cloud services** instead of Docker Compose
145+
146+
## Differences from Development Mode
147+
148+
| Aspect | Development (`pnpm dev`) | Production-like (Docker) |
149+
|--------|-------------------------|--------------------------|
150+
| Identity Provider | Test OIDC provider | Keycloak |
151+
| Authentication | Auto-login | Real login form |
152+
| User Management | Hardcoded test user | Keycloak admin UI |
153+
| Configuration | `.env.local` file | Environment variables |
154+
| Build | Development mode | Production build |
155+
| Performance | Slow (dev mode) | Fast (optimized) |
156+
157+
## Network Details
158+
159+
The Docker Compose setup creates an internal bridge network (`toolhive`):
160+
- App and Keycloak communicate via container names
161+
- External access via published ports (3000, 8080)
162+
- Browser connects to `localhost`, app connects to `keycloak` hostname

dev-auth/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@ The provider is pre-configured with:
3232
- **Supported Scopes**: openid, email, profile
3333
- **Redirect URIs**: Ports 3000-3003 supported
3434

35+
## Production-like Setup
36+
37+
For a production-like local environment with Keycloak, see [`DOCKER_DEPLOYMENT.md`](../DOCKER_DEPLOYMENT.md) in the root directory.
38+
39+
The Docker Compose setup includes:
40+
- Keycloak as a real identity provider
41+
- Next.js app in production mode
42+
- Proper authentication flow (no auto-login)
43+
3544
## For Production
3645

3746
Replace this with a real OIDC provider (Okta, Keycloak, Auth0, etc.) by updating the environment variables in `.env.local`:

dev-auth/keycloak-realm.json

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
{
2+
"id": "toolhive",
3+
"realm": "toolhive",
4+
"displayName": "ToolHive Cloud UI",
5+
"enabled": true,
6+
"sslRequired": "none",
7+
"registrationAllowed": false,
8+
"loginWithEmailAllowed": true,
9+
"duplicateEmailsAllowed": false,
10+
"resetPasswordAllowed": false,
11+
"editUsernameAllowed": false,
12+
"bruteForceProtected": true,
13+
"clients": [
14+
{
15+
"clientId": "toolhive-cloud-ui",
16+
"name": "ToolHive Cloud UI",
17+
"enabled": true,
18+
"protocol": "openid-connect",
19+
"publicClient": false,
20+
"secret": "toolhive-client-secret",
21+
"redirectUris": [
22+
"http://localhost:3000/api/auth/oauth2/callback/oidc",
23+
"http://localhost:3001/api/auth/oauth2/callback/oidc",
24+
"http://localhost:3002/api/auth/oauth2/callback/oidc",
25+
"http://localhost:3003/api/auth/oauth2/callback/oidc"
26+
],
27+
"webOrigins": [
28+
"http://localhost:3000",
29+
"http://localhost:3001",
30+
"http://localhost:3002",
31+
"http://localhost:3003"
32+
],
33+
"standardFlowEnabled": true,
34+
"directAccessGrantsEnabled": false,
35+
"serviceAccountsEnabled": false,
36+
"authorizationServicesEnabled": false,
37+
"fullScopeAllowed": true,
38+
"attributes": {
39+
"access.token.lifespan": "3600",
40+
"client.secret.creation.time": "0"
41+
},
42+
"defaultClientScopes": [
43+
"web-origins",
44+
"acr",
45+
"profile",
46+
"roles",
47+
"email"
48+
],
49+
"optionalClientScopes": [
50+
"address",
51+
"phone",
52+
"offline_access",
53+
"microprofile-jwt"
54+
]
55+
}
56+
],
57+
"users": [
58+
{
59+
"username": "test",
60+
"enabled": true,
61+
"emailVerified": true,
62+
"email": "[email protected]",
63+
"firstName": "Test",
64+
"lastName": "User",
65+
"credentials": [
66+
{
67+
"type": "password",
68+
"value": "test",
69+
"temporary": false
70+
}
71+
],
72+
"realmRoles": ["user"]
73+
}
74+
],
75+
"roles": {
76+
"realm": [
77+
{
78+
"name": "user",
79+
"description": "User role"
80+
}
81+
]
82+
},
83+
"defaultRole": {
84+
"name": "default-roles-toolhive",
85+
"description": "Default role for new users",
86+
"composite": true,
87+
"composites": {
88+
"realm": ["user"]
89+
}
90+
}
91+
}

docker-compose.yml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
services:
2+
# Keycloak Identity Provider
3+
keycloak:
4+
image: quay.io/keycloak/keycloak:26.0
5+
command: start-dev --import-realm
6+
environment:
7+
# Admin credentials
8+
KEYCLOAK_ADMIN: admin
9+
KEYCLOAK_ADMIN_PASSWORD: admin
10+
# Database (dev mode uses H2)
11+
KC_DB: dev-mem
12+
# Hostname configuration
13+
KC_HOSTNAME_STRICT: false
14+
KC_HOSTNAME_STRICT_HTTPS: false
15+
KC_HTTP_ENABLED: true
16+
ports:
17+
- "8080:8080"
18+
volumes:
19+
# Import pre-configured realm on startup
20+
- ./dev-auth/keycloak-realm.json:/opt/keycloak/data/import/realm.json:ro
21+
healthcheck:
22+
test: ["CMD-SHELL", "timeout 1 bash -c '</dev/tcp/localhost/8080' || exit 1"]
23+
interval: 5s
24+
timeout: 2s
25+
retries: 10
26+
start_period: 40s
27+
networks:
28+
- toolhive
29+
30+
# Next.js Application
31+
# Using host network so app can access Keycloak on localhost:8080
32+
app:
33+
build:
34+
context: .
35+
dockerfile: Dockerfile
36+
environment:
37+
# Better Auth configuration
38+
BETTER_AUTH_SECRET: "local-dev-secret-change-in-production-min-32-chars"
39+
BETTER_AUTH_URL: "http://localhost:3003"
40+
# Trusted origins
41+
TRUSTED_ORIGINS: "http://localhost:3003"
42+
# OIDC/Keycloak configuration
43+
# Using localhost:8080 - accessible from both browser and container
44+
OIDC_ISSUER_URL: "http://localhost:8080/realms/toolhive"
45+
OIDC_CLIENT_ID: "toolhive-cloud-ui"
46+
OIDC_CLIENT_SECRET: "toolhive-client-secret"
47+
# Override container port since we're using host network
48+
PORT: "3003"
49+
network_mode: "host"
50+
51+
networks:
52+
toolhive:
53+
driver: bridge

0 commit comments

Comments
 (0)