This application uses OAuth2 Proxy for authentication, enabling integration with external identity providers like Keycloak, Google, and GitHub.
Why Authentication Matters: Full functionality—including user sessions, personalized research history, document access controls, and multi-user collaboration—requires proper authentication. The mock OAuth mode provides a fully functional auth experience for local development.
| Mode | When to Use | Setup Time |
|---|---|---|
| Mock OAuth (local) | Local development with auth (recommended) | 1 minute |
| No auth (local) | Quick exploration, UI development only | 1 minute |
| Real OAuth (local) | Testing with actual provider | 15 minutes |
| OAuth (OpenShift) | Production deployment | 20 minutes |
┌─────────────────────┐
│ OpenShift Route │
│ (External Access) │
└──────────┬──────────┘
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ App Pod │
│ ┌────────────────┐ │
│ │ OAuth2 Proxy │◄── All external requests enter here │
│ │ (Port 4180) │ │
│ │ │ - Authenticates users │
│ │ ENTRY POINT │ - Sets X-Forwarded-User headers │
│ └───────┬────────┘ - Redirects to OAuth provider │
│ │ │
│ ▼ │
│ ┌────────────────┐ │
│ │ Frontend │ - Serves React static files │
│ │ (Port 8080) │ - Proxies /api/* to backend │
│ │ Nginx Proxy │ │
│ └───────┬────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────┐ │
│ │ Backend │ - Reads X-Forwarded-User headers │
│ │ (Port 8000) │ - Auto-creates users on first login │
│ │ │ - Trusts headers (internal only) │
│ │ INTERNAL ONLY │◄── NOT directly accessible from outside │
│ └────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
SECURITY NOTE: The backend trusts X-Forwarded-* headers because it is only
accessible through the OAuth2 Proxy. Never expose the backend directly to external traffic.
- User accesses the application via the OpenShift route
- OAuth2 Proxy intercepts requests and checks for valid authentication
- Unauthenticated users are redirected to the OAuth provider (Keycloak/Google/GitHub)
- After successful login, OAuth2 Proxy sets headers:
X-Forwarded-User: Username from OAuth providerX-Forwarded-Email: User's email addressX-Forwarded-Preferred-Username: Preferred username
- Backend reads these headers and auto-creates users on first login
- Logout redirects to
/oauth2/sign_outwhich clears the session
The easiest way to develop with full authentication is using the built-in mock OAuth server. No external credentials required.
# Start all services including mock OAuth
make services-start
# Start frontend and backend
make devThe make dev command auto-detects OAuth and displays the access URL:
OAuth running - access app at: http://localhost:4180
How Mock OAuth Works:
- Uses mock-oauth2-server container
- Auto-starts when no real OAuth credentials are configured
- Login with any username/password (they're not validated)
- Full OAuth flow with user headers (
X-Forwarded-User,X-Forwarded-Email) - Backend auto-creates users on first login
Ports:
4180- OAuth2 Proxy (entry point - use this URL)9099- Mock OAuth server (internal)8080- Frontend (proxied through OAuth)8000- Backend (internal)
For quick UI development without OAuth overhead:
# Edit backend/.env
ENVIRONMENT=local
# Start the app (without services-start)
make db-start && make db-init
make devIn local mode:
- No authentication headers are required
- A default "dev-user" is used for all requests
- The frontend will show "dev-user@example.com" in the user menu
- Access the app directly at http://localhost:8080
For testing with actual OAuth providers (Google, GitHub, Keycloak), configure credentials in backend/.env.
# Generic OAuth (works with any OIDC provider)
OAUTH_CLIENT_ID=your-client-id
OAUTH_CLIENT_SECRET=your-client-secret
OAUTH_ISSUER_URL=https://your-oidc-provider.com # Optional: enables OIDC mode
OAUTH_COOKIE_SECRET=<auto-generated-if-not-set>Provider Auto-Detection:
- If
OAUTH_ISSUER_URLis set → Uses OIDC provider (Keycloak, Okta, etc.) - If
OAUTH_ISSUER_URLis not set → Uses Google provider - If
OAUTH_CLIENT_IDis not set → Uses mock OAuth server
This section provides step-by-step instructions for setting up Google OAuth for both local development and OpenShift deployment.
Official Documentation:
- Setting up OAuth 2.0 - Google Cloud support guide
- Using OAuth 2.0 for Web Server Applications - Developer guide
- OAuth 2.0 Scopes for Google APIs - Available scopes
-
Go to Google Cloud Console
- Open Google Cloud Console - Credentials
- Sign in with your Google account
-
Select or Create a Project
- Click the project dropdown at the top
- Select an existing project or click "New Project"
- If creating new: Enter a project name (e.g., "Deep Research Dev")
-
Configure OAuth Consent Screen (first time only)
- In the left sidebar, click "OAuth consent screen"
- Choose "External" (unless you have Google Workspace)
- Fill in required fields:
- App name: Deep Research
- User support email: Your email
- Developer contact email: Your email
- Click "Save and Continue" through the remaining steps
- Add your email as a test user if in "Testing" mode
-
Create OAuth 2.0 Credentials
- Go back to "Credentials" in the left sidebar
- Click "+ CREATE CREDENTIALS" → "OAuth client ID"
- Select Application type: "Web application"
- Name: "Deep Research Local" (or "Deep Research Production")
- Authorized JavaScript origins: (see environment-specific sections below)
- Authorized redirect URIs: (see environment-specific sections below)
- Click "Create"
-
Copy Your Credentials
- A dialog will show your Client ID and Client Secret
- Save these securely—you'll need them for configuration
After creating Google OAuth credentials, configure them for local development.
Authorized Origins & Redirect URIs (in Google Console):
Authorized JavaScript origins:
http://localhost:4180
Authorized redirect URIs:
http://localhost:4180/oauth2/callback
Configure the Application:
# Edit backend/.env with your credentials
cp backend/.env.example backend/.envAdd these values to backend/.env:
ENVIRONMENT=development
OAUTH_CLIENT_ID=your-client-id.apps.googleusercontent.com
OAUTH_CLIENT_SECRET=your-client-secret
# OAUTH_COOKIE_SECRET is auto-generated if not setStart the Application:
make services-start
make devAccess the App:
- Open http://localhost:4180 (OAuth proxy port)
- You'll be redirected to Google sign-in
- After authentication, you'll return to the app
After creating Google OAuth credentials, configure them for cluster deployment.
Authorized Origins & Redirect URIs (in Google Console):
Get your route URL first:
# After initial deploy, or estimate based on cluster:
# https://multi-agent-platform-<namespace>.apps.<cluster-domain>Then add to Google Console:
Authorized JavaScript origins:
https://multi-agent-platform-multi-agent-platform-dev.apps.your-cluster.com
Authorized redirect URIs:
https://multi-agent-platform-multi-agent-platform-dev.apps.your-cluster.com/oauth2/callback
Configure the OAuth Secret:
# Copy the example file
cp k8s/app/overlays/dev/oauth-proxy-secret.env.example \
k8s/app/overlays/dev/oauth-proxy-secret.env
# Edit with your credentialsContents of oauth-proxy-secret.env:
# Generate cookie secret: python -c "import secrets; print(secrets.token_urlsafe(32))"
cookie-secret=your-generated-cookie-secret
# From Google Cloud Console
client-id=your-client-id.apps.googleusercontent.com
client-secret=your-client-secretDeploy:
oc login --server=https://your-cluster
make deployUpdate Google Console (if redirect URL changed):
- After deployment, get the actual route URL:
oc get route multi-agent-platform -n multi-agent-platform-dev -o jsonpath='{.spec.host}' - Update the authorized redirect URI in Google Console if needed
- Create a new client in your Keycloak realm
- Set Access Type to "confidential"
- Add valid redirect URI:
https://your-app.example.com/oauth2/callback - Copy the client ID and secret
# oauth2-proxy-secret.yaml
stringData:
OAUTH2_PROXY_PROVIDER: "oidc"
OAUTH2_PROXY_OIDC_ISSUER_URL: "https://keycloak.example.com/realms/your-realm"
OAUTH2_PROXY_CLIENT_ID: "your-client-id"
OAUTH2_PROXY_CLIENT_SECRET: "your-client-secret"
OAUTH2_PROXY_COOKIE_SECRET: "<generated-secret>"- Go to GitHub Settings > Developer settings > OAuth Apps
- Click "New OAuth App"
- Fill in:
- Application name: Deep Research
- Homepage URL: Your app URL
- Authorization callback URL:
https://your-app.example.com/oauth2/callback
- Copy the Client ID and generate a Client Secret
# oauth2-proxy-secret.yaml
stringData:
OAUTH2_PROXY_PROVIDER: "github"
OAUTH2_PROXY_CLIENT_ID: "your-github-client-id"
OAUTH2_PROXY_CLIENT_SECRET: "your-github-client-secret"
OAUTH2_PROXY_COOKIE_SECRET: "<generated-secret>"
# Optional: Restrict to organization members
OAUTH2_PROXY_GITHUB_ORG: "your-org"The backend reads authentication mode from the ENVIRONMENT variable:
| ENVIRONMENT | Behavior |
|---|---|
local |
No auth required, uses dev-user fallback |
development |
Reads OAuth headers, auto-creates users |
production |
Reads OAuth headers, auto-creates users |
When a user authenticates via OAuth2 Proxy:
- Backend checks for existing user by username
- If not found, creates a new user with:
username: FromX-Forwarded-Preferred-UsernameorX-Forwarded-Useremail: FromX-Forwarded-Emailactive:trueadmin:false(can be changed via admin panel)
- Updates
last_logintimestamp
The frontend handles authentication through:
- AppContext: Fetches current user from
/api/v1/users/me - User Menu: Displays username with logout option
- API Client: Intercepts 401 responses and redirects to OAuth login
- Logout: Redirects to
/oauth2/sign_out
- Never commit OAuth2 proxy secrets to version control
- Use HTTPS for all OAuth callbacks
- Restrict email domains if needed via
OAUTH2_PROXY_EMAIL_DOMAINS - Set appropriate cookie security flags in production
- Validate OAuth headers only come from the proxy (not user-supplied)
The SQLAdmin panel (/admin) provides database management capabilities. In production:
- Network Policy: Restrict
/adminaccess via OpenShift NetworkPolicy or OAuth2 proxy skip rules - Admin Role: Consider requiring
is_admin=Truefor admin panel access - Audit Logging: Admin actions are logged via request middleware
Example: Restrict admin access to specific users:
# In oauth2-proxy config, add skip rule with user restriction
OAUTH2_PROXY_SKIP_AUTH_ROUTES: "/api/v1/utils/health-check"
# Admin is NOT in skip routes, so it requires authenticationThe GraphQL endpoint (/api/graphql) has built-in security:
- Authentication Required: All queries require OAuth authentication (except in local dev mode)
- Query Depth Limit: Maximum depth of 10 prevents deeply nested attacks
- Token Limit: Maximum 2000 tokens per query prevents DoS
- GraphiQL Playground: Enabled but protected by OAuth (safe in production)
Production Considerations:
- Consider disabling GraphQL introspection for additional security
- Monitor query complexity via logging middleware
Check that OAuth2 Proxy is passing headers:
curl -H "X-Forwarded-User: test" -H "X-Forwarded-Email: test@example.com" \
http://localhost:8000/api/v1/users/meEnsure ENVIRONMENT=local is set in your .env file.
If login loops occur, check:
- Cookie domain matches your app domain
- HTTPS is properly configured
- Cookie secret is properly set
