Frontend Client Configuration¶
This guide explains how to configure the authentication-test-frontend client in Keycloak for the Next.js frontend application.
Overview¶
The frontend application requires its own OAuth 2.0 client in Keycloak, separate from the API server client. This client handles user authentication via the Authorization Code Flow with PKCE.
Prerequisites¶
- Keycloak installed and running
secure-testrealm created- Access to Keycloak Admin Console
- Admin credentials for Keycloak
Client Configuration¶
Step 1: Create Frontend Client¶
-
Log into Keycloak Admin Console
- URL:
https://keycloak.lab.home/admin - Select realm: secure-test
- URL:
-
Navigate to Clients
- Click Clients in the left sidebar
- Click Create client button
-
General Settings
- Client type:
OpenID Connect - Client ID:
authentication-test-frontend - Click Next
- Client type:
-
Capability Config
- Client authentication: ✓ ON (Confidential client)
- Authorization: ✗ OFF
- Authentication flow:
- ✓ Standard flow (Authorization Code Flow)
- ✓ Direct access grants (Optional, for testing)
- ✗ Implicit flow
- ✗ Service account roles
- Click Next
-
Login Settings
- Root URL:
http://localhost:3000 - Home URL:
http://localhost:3000 - Valid redirect URIs:
- Valid post logout redirect URIs:
- Web origins (for CORS):
- Click Save
- Root URL:
-
Get Client Secret
- Go to Credentials tab
- Copy the Client Secret value
- Save this securely for the frontend
.env.localfile
# Step 1: Get admin access token
TOKEN=$(curl -s -X POST "https://keycloak.lab.home/realms/master/protocol/openid-connect/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=admin" \
-d "password=your-admin-password" \
-d "grant_type=password" \
-d "client_id=admin-cli" \
| python3 -c "import sys, json; print(json.load(sys.stdin)['access_token'])")
# Step 2: Create frontend client
curl -X POST "https://keycloak.lab.home/admin/realms/secure-test/clients" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"clientId": "authentication-test-frontend",
"name": "Authentication Test Frontend",
"description": "Next.js frontend application for TaskFlow",
"enabled": true,
"protocol": "openid-connect",
"publicClient": false,
"clientAuthenticatorType": "client-secret",
"standardFlowEnabled": true,
"directAccessGrantsEnabled": true,
"serviceAccountsEnabled": false,
"authorizationServicesEnabled": false,
"rootUrl": "http://localhost:3000",
"baseUrl": "http://localhost:3000",
"redirectUris": [
"http://localhost:3000/*",
"http://localhost:3000/api/auth/callback/keycloak",
"https://app.lab.home/*",
"https://app.lab.home/api/auth/callback/keycloak"
],
"webOrigins": [
"http://localhost:3000",
"https://app.lab.home"
],
"attributes": {
"pkce.code.challenge.method": "S256"
}
}'
# Step 3: Get the client details including secret
CLIENT_UUID=$(curl -s "https://keycloak.lab.home/admin/realms/secure-test/clients?clientId=authentication-test-frontend" \
-H "Authorization: Bearer $TOKEN" \
| python3 -c "import sys, json; print(json.load(sys.stdin)[0]['id'])")
# Step 4: Retrieve client secret
curl -s "https://keycloak.lab.home/admin/realms/secure-test/clients/$CLIENT_UUID/client-secret" \
-H "Authorization: Bearer $TOKEN" \
| python3 -c "import sys, json; print('Client Secret:', json.load(sys.stdin)['value'])"
Automated Setup Complete
The client has been created and configured. Copy the client secret from the output for use in your .env.local file.
Step 2: Configure Environment Variables¶
After creating the client and obtaining the secret, configure your frontend application:
# Navigate to frontend directory
cd Frontend
# Copy environment template
cp .env.local.example .env.local
# Edit .env.local with your values
Update .env.local with the following:
# Keycloak Configuration
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=<generate-with-openssl-rand-base64-32>
# Keycloak OAuth Provider
KEYCLOAK_ID=authentication-test-frontend
KEYCLOAK_SECRET=<client-secret-from-keycloak>
KEYCLOAK_ISSUER=https://keycloak.lab.home/realms/secure-test
# API Server Configuration
NEXT_PUBLIC_API_URL=http://localhost:9080
Step 3: Generate NextAuth Secret¶
Generate a secure random secret for NextAuth:
Copy the output and set it as NEXTAUTH_SECRET in .env.local.
Client Configuration Details¶
Authentication Flow¶
The frontend uses the Authorization Code Flow with PKCE (Proof Key for Code Exchange):
- User clicks "Sign In"
- Frontend redirects to Keycloak login page
- User enters credentials
- Keycloak validates and redirects back with authorization code
- Frontend exchanges code for access token (with PKCE verification)
- Session created with user info and tokens
PKCE (Proof Key for Code Exchange)¶
PKCE adds security to the Authorization Code Flow:
- Code Challenge: Generated by frontend before redirect
- Code Verifier: Sent when exchanging authorization code
- Method: S256 (SHA-256 hash)
- Purpose: Prevents authorization code interception attacks
Token Storage¶
- Access Token: Stored in HTTP-only cookie (not accessible to JavaScript)
- Refresh Token: Stored in HTTP-only cookie
- ID Token: Stored in HTTP-only cookie
- Session: Managed by NextAuth.js
Redirect URIs Explained¶
Valid Redirect URIs¶
These URIs are where Keycloak can redirect after authentication:
http://localhost:3000/* # Development (wildcard)
http://localhost:3000/api/auth/callback/keycloak # NextAuth callback (specific)
https://app.lab.home/* # Production (wildcard)
https://app.lab.home/api/auth/callback/keycloak # Production callback (specific)
Exact Match Required
The callback URI must match exactly. NextAuth uses /api/auth/callback/keycloak by default.
Web Origins (CORS)¶
These origins are allowed to make cross-origin requests:
Verification Steps¶
1. Verify Client Creation¶
- Navigate to Clients
- Find
authentication-test-frontendin the list - Verify Enabled is ON
- Check Client authentication is ON
2. Test Authentication Flow¶
-
Start frontend application:
-
Open browser: http://localhost:3000
-
Click "Sign In":
- Should redirect to Keycloak login page
- URL should be:
https://keycloak.lab.home/realms/secure-test/protocol/openid-connect/auth?...
-
Enter credentials:
- Use a test user with
schedule-userrole - Should redirect back to application
- Use a test user with
-
Verify success:
- Username should appear in header
- Session should be active
- Can access
/apppage
3. Verify Token Contents¶
After successful login, check the token:
# In browser console (F12)
# Note: Tokens are in HTTP-only cookies, so you can't access them directly
# But you can verify the session:
fetch('/api/auth/session').then(r => r.json()).then(console.log)
Expected session structure:
{
"user": {
"name": "John Doe",
"email": "john.doe@example.com"
},
"expires": "2026-02-28T10:00:00.000Z"
}
Troubleshooting¶
Issue: "Invalid redirect URI"¶
Cause: Redirect URI mismatch between NextAuth and Keycloak
Solution:
- Check the exact URI in browser when error occurs
- Add that URI to Valid redirect URIs in Keycloak
- Ensure it includes
/api/auth/callback/keycloak - Restart frontend application
Issue: "CORS error"¶
Cause: Frontend origin not in Web origins
Solution:
- Add
http://localhost:3000to Web origins - Ensure no trailing slash
- Match protocol (http/https) exactly
- Save and test again
Issue: "Client authentication failed"¶
Cause: Client secret mismatch
Solution:
- Go to Keycloak → Clients → authentication-test-frontend → Credentials
- Copy the client secret
- Update
KEYCLOAK_SECRETin.env.local - Restart frontend:
npm run dev
Issue: "Session not persisting"¶
Cause: NEXTAUTH_SECRET not set or invalid
Solution:
- Generate new secret:
openssl rand -base64 32 - Set
NEXTAUTH_SECRETin.env.local - Clear browser cookies
- Restart frontend
- Try logging in again
Issue: "Token expired" errors¶
Cause: Token lifespan too short
Solution:
- Go to Keycloak → Realm Settings → Tokens
- Increase Access Token Lifespan (default: 5 minutes)
- Increase SSO Session Idle (default: 30 minutes)
- Save and test again
Advanced Configuration¶
Custom Token Lifespan¶
To customize token lifespan for this client:
- Go to Clients → authentication-test-frontend → Advanced tab
- Set Access Token Lifespan:
15 Minutes - Set Client Session Idle:
30 Minutes - Set Client Session Max:
10 Hours - Click Save
Add Custom Claims¶
To add custom claims to tokens:
- Go to Clients → authentication-test-frontend → Client scopes
- Click authentication-test-frontend-dedicated
- Go to Mappers tab
- Click Add mapper → By configuration
- Select mapper type (e.g., User Attribute)
- Configure and save
Audience Validation¶
To add audience claim:
- Go to Client scopes → authentication-test-frontend-dedicated → Mappers
- Click Add mapper → By configuration
- Select Audience
- Configure:
- Name:
audience - Included Client Audience:
authentication-test-frontend - Add to access token: ✓ ON
- Name:
- Click Save
Production Deployment¶
Update for Production¶
When deploying to production:
-
Update Keycloak client:
- Add production redirect URIs
- Add production web origins
- Update root/home URLs
-
Update frontend environment:
-
Security checklist:
- [ ] Use HTTPS for all URLs
- [ ] Generate new NEXTAUTH_SECRET for production
- [ ] Use different client secret than development
- [ ] Enable rate limiting
- [ ] Monitor authentication logs
- [ ] Set up session timeout alerts
Environment-Specific Clients¶
Consider creating separate clients for each environment:
authentication-test-frontend-dev- Developmentauthentication-test-frontend-staging- Stagingauthentication-test-frontend-prod- Production
Benefits: - Separate secrets per environment - Different token lifespans - Isolated configuration - Better security
Security Best Practices¶
1. Client Secret Management¶
- Never commit client secrets to version control
- Use environment variables or secret management systems
- Rotate secrets periodically (every 90 days)
- Use different secrets for dev/staging/production
2. Redirect URI Security¶
- Use specific URIs when possible (avoid wildcards in production)
- Always use HTTPS in production
- Validate redirect URIs on both client and server
- Never allow open redirects
3. Token Security¶
- Tokens stored in HTTP-only cookies (not accessible to JavaScript)
- Automatic token refresh before expiration
- Logout clears all session data
- Short token lifespans (5-15 minutes for access tokens)
4. CORS Configuration¶
- Restrict web origins to specific domains
- Never use wildcard (*) in production
- Match protocol and port exactly
- Review origins regularly
Next Steps¶
After configuring the frontend client:
- Frontend Setup Guide - Install and run the application
- Frontend Configuration - Detailed environment setup
- Authentication Flow - Understand the auth process
- API Integration - Connect to backend API